Files
astro/packages/astro/CHANGELOG.md
Houston (Bot) 141c676df1 [ci] release (#14930)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-12-03 17:01:59 +00:00

385 KiB
Raw Permalink Blame History

astro

5.16.4

Patch Changes

  • #14940 2cf79c2 Thanks @ematipico! - Fixes a bug where Astro didn't properly combine CSP resources from the csp configuration with those added using the runtime API (Astro.csp.insertDirective()) to form grammatically correct CSP headers

    Now Astro correctly deduplicate CSP resources. For example, if you have a global resource in the configuration file, and then you add a a new one using the runtime APIs.

5.16.3

Patch Changes

  • #14889 4bceeb0 Thanks @florian-lefebvre! - Fixes actions types when using specific TypeScript configurations

  • #14929 e0f277d Thanks @matthewp! - Fixes authentication bypass via double URL encoding in middleware

    Prevents attackers from bypassing path-based authentication checks using multi-level URL encoding (e.g., /%2561dmin instead of /%61dmin). Pathnames are now validated after decoding to ensure no additional encoding remains.

5.16.2

Patch Changes

5.16.1

Patch Changes

5.16.0

Minor Changes

  • #13880 1a2ed01 Thanks @azat-io! - Adds experimental SVGO optimization support for SVG assets

    Astro now supports automatic SVG optimization using SVGO during build time. This experimental feature helps reduce SVG file sizes while maintaining visual quality, improving your site's performance.

    To enable SVG optimization with default settings, add the following to your astro.config.mjs:

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

    To customize optimization, pass a SVGO configuration object:

    export default defineConfig({
      experimental: {
        svgo: {
          plugins: [
            'preset-default',
            {
              name: 'removeViewBox',
              active: false,
            },
          ],
        },
      },
    });
    

    For more information on enabling and using this feature in your project, see the experimental SVG optimization docs.

  • #14810 2e845fe Thanks @ascorbic! - Adds a hint for code agents to use the --yes flag to skip prompts when running astro add

  • #14698 f42ff9b Thanks @mauriciabad! - Adds the ActionInputSchema utility type to automatically infer the TypeScript type of an action's input based on its Zod schema

    For example, this type can be used to retrieve the input type of a form action:

    import { type ActionInputSchema, defineAction } from 'astro:actions';
    import { z } from 'astro/zod';
    
    const action = defineAction({
      accept: 'form',
      input: z.object({ name: z.string() }),
      handler: ({ name }) => ({ message: `Welcome, ${name}!` }),
    });
    
    type Schema = ActionInputSchema<typeof action>;
    // typeof z.object({ name: z.string() })
    
    type Input = z.input<Schema>;
    // { name: string }
    
  • #14574 4356485 Thanks @jacobdalamb! - Adds new CLI shortcuts available when running astro preview:

    • o + enter: open the site in your browser
    • q + enter: quit the preview
    • h + enter: print all available shortcuts

Patch Changes

  • #14813 e1dd377 Thanks @ematipico! - Removes picocolors as dependency in favor of the fork piccolore.

  • #14609 d774306 Thanks @florian-lefebvre! - Improves astro info

  • #14796 c29a785 Thanks @florian-lefebvre! - BREAKING CHANGE to the experimental Fonts API only

    Updates the default subsets to ["latin"]

    Subsets have been a common source of confusion: they caused a lot of files to be downloaded by default. You now have to manually pick extra subsets.

    Review your Astro config and update subsets if you need, for example if you need greek characters:

    import { defineConfig, fontProviders } from "astro/config"
    
    export default defineConfig({
        experimental: {
            fonts: [{
                name: "Roboto",
                cssVariable: "--font-roboto",
                provider: fontProviders.google(),
    +            subsets: ["latin", "greek"]
            }]
        }
    })
    

5.15.9

Patch Changes

  • #14786 758a891 Thanks @mef! - Add handling of invalid encrypted props and slots in server islands.

  • #14783 504958f Thanks @florian-lefebvre! - Improves the experimental Fonts API build log to show the number of downloaded files. This can help spotting excessive downloading because of misconfiguration

  • #14791 9e9c528 Thanks @Princesseuh! - Changes the remote protocol checks for images to require explicit authorization in order to use data URIs.

    In order to allow data URIs for remote images, you will need to update your astro.config.mjs file to include the following configuration:

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      images: {
        remotePatterns: [
          {
            protocol: 'data',
          },
        ],
      },
    });
    
  • #14787 0f75f6b Thanks @matthewp! - Fixes wildcard hostname pattern matching to correctly reject hostnames without dots

    Previously, hostnames like localhost or other single-part names would incorrectly match patterns like *.example.com. The wildcard matching logic has been corrected to ensure that only valid subdomains matching the pattern are accepted.

  • #14776 3537876 Thanks @ktym4a! - Fixes the behavior of passthroughImageService so it does not generate webp.

  • Updated dependencies [9e9c528, 0f75f6b]:

    • @astrojs/internal-helpers@0.7.5
    • @astrojs/markdown-remark@6.3.9

5.15.8

Patch Changes

  • #14772 00c579a Thanks @matthewp! - Improves the security of Server Islands slots by encrypting them before transmission to the browser, matching the security model used for props. This improves the integrity of slot content and prevents injection attacks, even when component templates don't explicitly support slots.

    Slots continue to work as expected for normal usage—this change has no breaking changes for legitimate requests.

  • #14771 6f80081 Thanks @matthewp! - Fix middleware pathname matching by normalizing URL-encoded paths

    Middleware now receives normalized pathname values, ensuring that encoded paths like /%61dmin are properly decoded to /admin before middleware checks. This prevents potential security issues where middleware checks might be bypassed through URL encoding.

5.15.7

Patch Changes

  • #14765 03fb47c Thanks @florian-lefebvre! - Fixes a case where process.env wouldn't be properly populated during the build

  • #14690 ae7197d Thanks @fredriknorlin! - Fixes a bug where Astro's i18n fallback system with fallbackType: 'rewrite' would not generate fallback files for pages whose filename started with a locale key.

5.15.6

Patch Changes

  • #14751 18c55e1 Thanks @delucis! - Fixes hydration of client components when running the dev server and using a barrel file that re-exports both Astro and UI framework components.

  • #14750 35122c2 Thanks @florian-lefebvre! - Updates the experimental Fonts API to log a warning if families with a conflicting cssVariable are provided

  • #14737 74c8852 Thanks @Arecsu! - Fixes an error when using transition:persist with components that use declarative Shadow DOM. Astro now avoids re-attaching a shadow root if one already exists, preventing "Unable to re-attach to existing ShadowDOM" navigation errors.

  • #14750 35122c2 Thanks @florian-lefebvre! - Updates the experimental Fonts API to allow for more granular configuration of remote font families

    A font family is defined by a combination of properties such as weights and styles (e.g. weights: [500, 600] and styles: ["normal", "bold"]), but you may want to download only certain combinations of these.

    For greater control over which font files are downloaded, you can specify the same font (ie. with the same cssVariable, name, and provider properties) multiple times with different combinations. Astro will merge the results and download only the required files. For example, it is possible to download normal 500 and 600 while downloading only italic 500:

    // astro.config.mjs
    import { defineConfig, fontProviders } from 'astro/config';
    
    export default defineConfig({
      experimental: {
        fonts: [
          {
            name: 'Roboto',
            cssVariable: '--roboto',
            provider: fontProviders.google(),
            weights: [500, 600],
            styles: ['normal'],
          },
          {
            name: 'Roboto',
            cssVariable: '--roboto',
            provider: fontProviders.google(),
            weights: [500],
            styles: ['italic'],
          },
        ],
      },
    });
    

5.15.5

Patch Changes

  • #14712 91780cf Thanks @florian-lefebvre! - Fixes a case where build's process.env would be inlined in the server output

  • #14713 666d5a7 Thanks @florian-lefebvre! - Improves fallbacks generation when using the experimental Fonts API

  • #14743 dafbb1b Thanks @matthewp! - Improves X-Forwarded header validation to prevent cache poisoning and header injection attacks. Now properly validates X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-Port headers against configured allowedDomains patterns, rejecting malformed or suspicious values. This is especially important when running behind a reverse proxy or load balancer.

5.15.4

Patch Changes

  • #14703 970ac0f Thanks @ArmandPhilippot! - Adds missing documentation for some public utilities exported from astro:i18n.

  • #14715 3d55c5d Thanks @ascorbic! - Adds support for client hydration in getContainerRenderer()

    The getContainerRenderer() function is exported by Astro framework integrations to simplify the process of rendering framework components when using the experimental Container API inside a Vite or Vitest environment. This update adds the client hydration entrypoint to the returned object, enabling client-side interactivity for components rendered using this function. Previously this required users to manually call container.addClientRenderer() with the appropriate client renderer entrypoint.

    See the container-with-vitest demo for a usage example, and the Container API documentation for more information on using framework components with the experimental Container API.

  • #14711 a4d284d Thanks @deining! - Fixes typos in documenting our error messages and public APIs.

  • #14701 9be54c7 Thanks @florian-lefebvre! - Fixes a case where the experimental Fonts API would filter available font files too aggressively, which could prevent the download of woff files when using the google provider

5.15.3

Patch Changes

  • #14627 b368de0 Thanks @matthewp! - Fixes skew protection support for images and font URLs

    Adapter-level query parameters (assetQueryParams) are now applied to all image and font asset URLs, including:

    • Dynamic optimized images via /_image endpoint
    • Static optimized image files
    • Font preload tags and font requests when using the experimental Fonts API
  • #14631 3ad33f9 Thanks @KurtGokhan! - Adds the astro/jsx-dev-runtime export as an alias for astro/jsx-runtime

5.15.2

Patch Changes

  • #14623 c5fe295 Thanks @delucis! - Fixes a leak of server runtime code when importing SVGs in client-side code. Previously, when importing an SVG file in client code, Astro could end up adding code for rendering SVGs on the server to the client bundle.

  • #14621 e3175d9 Thanks @GameRoMan! - Updates vite version to fix CVE

5.15.1

Patch Changes

  • #14612 18552c7 Thanks @ematipico! - Fixes a regression introduced in Astro v5.14.7 that caused ?url imports to not work correctly. This release reverts #14142.

5.15.0

Minor Changes

  • #14543 9b3241d Thanks @matthewp! - Adds two new adapter configuration options assetQueryParams and internalFetchHeaders to the Adapter API.

    Official and community-built adapters can now use client.assetQueryParams to specify query parameters that should be appended to asset URLs (CSS, JavaScript, images, fonts, etc.). The query parameters are automatically appended to all generated asset URLs during the build process.

    Adapters can also use client.internalFetchHeaders to specify headers that should be included in Astro's internal fetch calls (Actions, View Transitions, Server Islands, Prefetch).

    This enables features like Netlify's skew protection, which requires the deploy ID to be sent with both internal requests and asset URLs to ensure client and server versions match during deployments.

  • #14489 add4277 Thanks @dev-shetty! - Adds a new Copy to Clipboard button to the error overlay stack trace.

    When an error occurs in dev mode, you can now copy the stack trace with a single click to more easily share it in a bug report, a support thread, or with your favorite LLM.

  • #14564 5e7cebb Thanks @florian-lefebvre! - Updates astro add cloudflare to scaffold more configuration files

    Running astro add cloudflare will now emit wrangler.jsonc and public/.assetsignore, allowing your Astro project to work out of the box as a worker.

Patch Changes

  • #14591 3e887ec Thanks @matthewp! - Adds TypeScript support for the components prop on MDX Content component when using await render(). Developers now get proper IntelliSense and type checking when passing custom components to override default MDX element rendering.

  • #14598 7b45c65 Thanks @delucis! - Reduces terminal text styling dependency size by switching from kleur to picocolors

  • #13826 8079482 Thanks @florian-lefebvre! - Adds the option to specify in the preload directive which weights, styles, or subsets to preload for a given font family when using the experimental Fonts API:

    ---
    import { Font } from 'astro:assets';
    ---
    
    <Font
      cssVariable="--font-roboto"
      preload={[{ subset: 'latin', style: 'normal' }, { weight: '400' }]}
    />
    

    Variable weight font files will be preloaded if any weight within its range is requested. For example, a font file for font weight 100 900 will be included when 400 is specified in a preload object.

5.14.8

Patch Changes

  • #14590 577d051 Thanks @matthewp! - Fixes image path resolution in content layer collections to support bare filenames. The image() helper now normalizes bare filenames like "cover.jpg" to relative paths "./cover.jpg" for consistent resolution behavior between markdown frontmatter and JSON content collections.

5.14.7

Patch Changes

  • #14582 7958c6b Thanks @florian-lefebvre! - Fixes a regression that caused Actions to throw errors while loading

  • #14567 94500bb Thanks @matthewp! - Fixes the actions endpoint to return 404 for non-existent actions instead of throwing an unhandled error

  • #14566 946fe68 Thanks @matthewp! - Fixes handling malformed cookies gracefully by returning the unparsed value instead of throwing

    When a cookie with an invalid value is present (e.g., containing invalid URI sequences), Astro.cookies.get() now returns the raw cookie value instead of throwing a URIError. This aligns with the behavior of the underlying cookie package and prevents crashes when manually-set or corrupted cookies are encountered.

  • #14142 73c5de9 Thanks @P4tt4te! - Updates handling of CSS for hydrated client components to prevent duplicates

  • #14576 2af62c6 Thanks @aprici7y! - Fixes a regression that caused Astro.site to always be undefined in getStaticPaths()

5.14.6

Patch Changes

  • #14562 722bba0 Thanks @erbierc! - Fixes a bug where the behavior of the "muted" HTML attribute was inconsistent with that of other attributes.

  • #14538 51ebe6a Thanks @florian-lefebvre! - Improves how Actions are implemented

  • #14548 6cdade4 Thanks @ascorbic! - Removes support for the maxAge property in cacheHint objects returned by live loaders.

    ⚠️ Breaking change for experimental live content collections only

    Feedback showed that this did not make sense to set at the loader level, since the loader does not know how long each individual entry should be cached for.

    If your live loader returns cache hints with maxAge, you need to remove this property:

    return {
      entries: [...],
      cacheHint: {
        tags: ['my-tag'],
    -   maxAge: 60,
        lastModified: new Date(),
      },
    };
    

    The cacheHint object now only supports tags and lastModified properties. If you want to set the max age for a page, you can set the headers manually:

    ---
    Astro.headers.set('cdn-cache-control', 'max-age=3600');
    ---
    
  • #14548 6cdade4 Thanks @ascorbic! - Adds missing rendered property to experimental live collections entry type

    Live collections support a rendered property that allows you to provide pre-rendered HTML for each entry. While this property was documented and implemented, it was missing from the TypeScript types. This could lead to type errors when trying to use it in a TypeScript project.

    No changes to your project code are necessary. You can continue to use the rendered property as before, and it will no longer produce TypeScript errors.

5.14.5

Patch Changes

  • #14525 4f55781 Thanks @penx! - Fixes defineLiveCollection() types

  • #14441 62ec8ea Thanks @upsuper! - Updates redirect handling to be consistent across static and server output, aligning with the behavior of other adapters.

    Previously, the Node.js adapter used default HTML files with meta refresh tags when in static output. This often resulted in an extra flash of the page on redirect, while also not applying the proper status code for redirections. It's also likely less friendly to search engines.

    This update ensures that configured redirects are always handled as HTTP redirects regardless of output mode, and the default HTML files for the redirects are no longer generated in static output. It makes the Node.js adapter more consistent with the other official adapters.

    No change to your project is required to take advantage of this new adapter functionality. It is not expected to cause any breaking changes. However, if you relied on the previous redirecting behavior, you may need to handle your redirects differently now. Otherwise you should notice smoother redirects, with more accurate HTTP status codes, and may potentially see some SEO gains.

  • #14506 ec3cbe1 Thanks @abdo-spices! - Updates the <Font /> component so that preload links are generated after the style tag, as recommended by capo.js

5.14.4

Patch Changes

  • #14509 7e04caf Thanks @ArmandPhilippot! - Fixes an error in the docs that specified an incorrect version for the security.allowedDomains release.

5.14.3

Patch Changes

  • #14505 28b2a1d Thanks @matthewp! - Fixes Cannot set property manifest error in test utilities by adding a protected setter for the manifest property

  • #14235 c4d84bb Thanks @toxeeec! - Fixes a bug where the "tap" prefetch strategy worked only on the first clicked link with view transitions enabled

5.14.2

Patch Changes

  • #14459 916f9c2 Thanks @florian-lefebvre! - Improves font files URLs in development when using the experimental fonts API by showing the subset if present

  • b8ca69b Thanks @ascorbic! - Aligns dev image server file base with Vite rules

  • #14469 1c090b0 Thanks @delucis! - Updates tinyexec dependency

  • #14460 008dc75 Thanks @florian-lefebvre! - Fixes a case where astro:config/server values typed as URLs would be serialized as strings

  • #13730 7260367 Thanks @razonyang! - Fixes a bug in i18n, where Astro caused an infinite loop when a locale that doesn't have an index, and Astro falls back to the index of the default locale.

  • 6ee63bf Thanks @matthewp! - Adds security.allowedDomains configuration to validate X-Forwarded-Host headers in SSR

    The X-Forwarded-Host header will now only be trusted if it matches one of the configured allowed host patterns. This prevents host header injection attacks that can lead to cache poisoning and other security vulnerabilities.

    Configure allowed host patterns to enable X-Forwarded-Host support:

    // astro.config.mjs
    export default defineConfig({
      output: 'server',
      adapter: node(),
      security: {
        allowedDomains: [
          { hostname: 'example.com' },
          { hostname: '*.example.com' },
          { hostname: 'cdn.example.com', port: '443' },
        ],
      },
    });
    

    The patterns support wildcards (* and **) for flexible hostname matching and can optionally specify protocol and port.

    Breaking change

    Previously, Astro.url would reflect the value of the X-Forwarded-Host header. While this header is commonly used by reverse proxies like Nginx to communicate the original host, it can be sent by any client, potentially allowing malicious actors to poison caches with incorrect URLs.

    If you were relying on X-Forwarded-Host support, add security.allowedDomains to your configuration to restore this functionality securely. When allowedDomains is not configured, X-Forwarded-Host headers are now ignored by default.

  • #14488 badc929 Thanks @olcanebrem! - Fixes a case where styles on the custom 500 error page would not be included

  • #14487 1e5b72c Thanks @florian-lefebvre! - Fixes a case where the URLs generated by the experimental Fonts API would be incorrect in dev

  • #14475 ae034ae Thanks @florian-lefebvre! - Warns if the font family name is not supported by the provider when using the experimental fonts API

  • b8ca69b Thanks @ascorbic! - Refactor remote path detection

  • #14468 2f2a5da Thanks @delucis! - Updates @capsizecss/unpack dependency

  • Updated dependencies [b8ca69b]:

    • @astrojs/internal-helpers@0.7.4
    • @astrojs/markdown-remark@6.3.8

5.14.1

Patch Changes

5.14.0

Minor Changes

  • #13520 a31edb8 Thanks @openscript! - Adds a new property routePattern available to GetStaticPathsOptions

    This provides the original, dynamic segment definition in a routing file path (e.g. /[...locale]/[files]/[slug]) from the Astro render context that would not otherwise be available within the scope of getStaticPaths(). This can be useful to calculate the params and props for each page route.

    For example, you can now localize your route segments and return an array of static paths by passing routePattern to a custom getLocalizedData() helper function. The params object will be set with explicit values for each route segment (e.g. locale, files, and slug). Then, these values will be used to generate the routes and can be used in your page template via Astro.params.

    ---
    // src/pages/[...locale]/[files]/[slug].astro
    import { getLocalizedData } from '../../../utils/i18n';
    
    export async function getStaticPaths({ routePattern }) {
      const response = await fetch('...');
      const data = await response.json();
    
      console.log(routePattern); // [...locale]/[files]/[slug]
    
      // Call your custom helper with `routePattern` to generate the static paths
      return data.flatMap((file) => getLocalizedData(file, routePattern));
    }
    
    const { locale, files, slug } = Astro.params;
    ---
    

    For more information about this advanced routing pattern, see Astro's routing reference.

  • #13651 dcfbd8c Thanks @ADTC! - Adds a new SvgComponent type

    You can now more easily enforce type safety for your .svg assets by directly importing SVGComponent from astro/types:

    ---
    // src/components/Logo.astro
    import type { SvgComponent } from 'astro/types';
    import HomeIcon from './Home.svg';
    interface Link {
      url: string;
      text: string;
      icon: SvgComponent;
    }
    const links: Link[] = [
      {
        url: '/',
        text: 'Home',
        icon: HomeIcon,
      },
    ];
    ---
    
  • #14206 16a23e2 Thanks @Fryuni! - Warn on prerendered routes collision.

    Previously, when two dynamic routes /[foo] and /[bar] returned values on their getStaticPaths that resulted in the same final path, only one of the routes would be rendered while the other would be silently ignored. Now, when this happens, a warning will be displayed explaining which routes collided and on which path.

    Additionally, a new experimental flag failOnPrerenderConflict can be used to fail the build when such a collision occurs.

Patch Changes

  • #13811 69572c0 Thanks @florian-lefebvre! - Adds a new getFontData() method to retrieve lower-level font family data programmatically when using the experimental Fonts API

    The getFontData() helper function from astro:assets provides access to font family data for use outside of Astro. This can then be used in an API Route or to generate your own meta tags.

    import { getFontData } from 'astro:assets';
    
    const data = getFontData('--font-roboto');
    

    For example, getFontData() can get the font buffer from the URL when using satori to generate OpenGraph images:

    // src/pages/og.png.ts
    
    import type { APIRoute } from 'astro';
    import { getFontData } from 'astro:assets';
    import satori from 'satori';
    
    export const GET: APIRoute = (context) => {
      const data = getFontData('--font-roboto');
    
      const svg = await satori(<div style={{ color: 'black' }}>hello, world</div>, {
        width: 600,
        height: 400,
        fonts: [
          {
            name: 'Roboto',
            data: await fetch(new URL(data[0].src[0].url, context.url.origin)).then((res) =>
              res.arrayBuffer(),
            ),
            weight: 400,
            style: 'normal',
          },
        ],
      });
    
      // ...
    };
    

    See the experimental Fonts API documentation for more information.

5.13.11

Patch Changes

  • #14409 250a595 Thanks @louisescher! - Fixes an issue where astro info would log errors to console in certain cases.

  • #14398 a7df80d Thanks @idawnlight! - Fixes an unsatisfiable type definition when calling addServerRenderer on an experimental container instance

  • #13747 120866f Thanks @jp-knj! - Adds automatic request signal abortion when the underlying socket closes in the Node.js adapter

    The Node.js adapter now automatically aborts the request.signal when the client connection is terminated. This enables better resource management and allows applications to properly handle client disconnections through the standard AbortSignal API.

  • #14428 32a8acb Thanks @drfuzzyness! - Force sharpService to return a Uint8Array if Sharp returns a SharedArrayBuffer

  • #14411 a601186 Thanks @GameRoMan! - Fixes relative links to docs that could not be opened in the editor.

5.13.10

Patch Changes

  • Updated dependencies [1e2499e]:
    • @astrojs/internal-helpers@0.7.3
    • @astrojs/markdown-remark@6.3.7

5.13.9

Patch Changes

5.13.8

Patch Changes

  • #14300 bd4a70b Thanks @louisescher! - Adds Vite version & integration versions to output of astro info

  • #14341 f75fd99 Thanks @delucis! - Fixes support for declarative Shadow DOM when using the <ClientRouter> component

  • #14350 f59581f Thanks @ascorbic! - Improves error reporting for content collections by adding logging for configuration errors that had previously been silently ignored. Also adds a new error that is thrown if a live collection is used in content.config.ts rather than live.config.ts.

  • #14343 13f7d36 Thanks @florian-lefebvre! - Fixes a regression in non node runtimes

5.13.7

Patch Changes

5.13.6

Patch Changes

5.13.5

Patch Changes

  • #14286 09c5db3 Thanks @ematipico! - BREAKING CHANGES only to the experimental CSP feature

    The following runtime APIs of the Astro global have been renamed:

    • Astro.insertDirective to Astro.csp.insertDirective
    • Astro.insertStyleResource to Astro.csp.insertStyleResource
    • Astro.insertStyleHash to Astro.csp.insertStyleHash
    • Astro.insertScriptResource to Astro.csp.insertScriptResource
    • Astro.insertScriptHash to Astro.csp.insertScriptHash

    The following runtime APIs of the APIContext have been renamed:

    • ctx.insertDirective to ctx.csp.insertDirective
    • ctx.insertStyleResource to ctx.csp.insertStyleResource
    • ctx.insertStyleHash to ctx.csp.insertStyleHash
    • ctx.insertScriptResource to ctx.csp.insertScriptResource
    • ctx.insertScriptHash to ctx.csp.insertScriptHash
  • #14283 3224637 Thanks @ematipico! - Fixes an issue where CSP headers were incorrectly injected in the development server.

  • #14275 3e2f20d Thanks @florian-lefebvre! - Adds support for experimental CSP when using experimental fonts

    Experimental fonts now integrate well with experimental CSP by injecting hashes for the styles it generates, as well as font-src directives.

    No action is required to benefit from it.

  • #14280 4b9fb73 Thanks @ascorbic! - Fixes a bug that caused cookies to not be correctly set when using middleware sequences

  • #14276 77281c4 Thanks @ArmandPhilippot! - Adds a missing export for resolveSrc, a documented image services utility.

5.13.4

Patch Changes

  • #14260 86a1e40 Thanks @jp-knj! - Fixes Astro.url.pathname to respect trailingSlash: 'never' configuration when using a base path. Previously, the root path with a base would incorrectly return /base/ instead of /base when trailingSlash was set to 'never'.

  • #14248 e81c4bd Thanks @julesyoungberg! - Fixes a bug where actions named 'apply' do not work due to being a function prototype method.

5.13.3

Patch Changes

  • #14239 d7d93e1 Thanks @wtchnm! - Fixes a bug where the types for the live content collections were not being generated correctly in dev mode

  • #14221 eadc9dd Thanks @delucis! - Fixes JSON schema support for content collections using the file() loader

  • #14229 1a9107a Thanks @jonmichaeldarby! - Ensures Astro.currentLocale returns the correct locale during SSG for pages that use a locale param (such as [locale].astro or [locale]/index.astro, which produce [locale].html)

5.13.2

Patch Changes

  • 4d16de7 Thanks @ematipico! - Improves the detection of remote paths in the _image endpoint. Now href parameters that start with // are considered remote paths.

  • Updated dependencies [4d16de7]:

    • @astrojs/internal-helpers@0.7.2
    • @astrojs/markdown-remark@6.3.6

5.13.1

Patch Changes

5.13.0

Minor Changes

  • #14173 39911b8 Thanks @florian-lefebvre! - Adds an experimental flag staticImportMetaEnv to disable the replacement of import.meta.env values with process.env calls and their coercion of environment variable values. This supersedes the rawEnvValues experimental flag, which is now removed.

    Astro allows you to configure a type-safe schema for your environment variables, and converts variables imported via astro:env into the expected type. This is the recommended way to use environment variables in Astro, as it allows you to easily see and manage whether your variables are public or secret, available on the client or only on the server at build time, and the data type of your values.

    However, you can still access environment variables through process.env and import.meta.env directly when needed. This was the only way to use environment variables in Astro before astro:env was added in Astro 5.0, and Astro's default handling of import.meta.env includes some logic that was only needed for earlier versions of Astro.

    The experimental.staticImportMetaEnv flag updates the behavior of import.meta.env to align with Vite's handling of environment variables and for better ease of use with Astro's current implementations and features. This will become the default behavior in Astro 6.0, and this early preview is introduced as an experimental feature.

    Currently, non-public import.meta.env environment variables are replaced by a reference to process.env. Additionally, Astro may also convert the value type of your environment variables used through import.meta.env, which can prevent access to some values such as the strings "true" (which is converted to a boolean value), and "1" (which is converted to a number).

    The experimental.staticImportMetaEnv flag simplifies Astro's default behavior, making it easier to understand and use. Astro will no longer replace any import.meta.env environment variables with a process.env call, nor will it coerce values.

    To enable this feature, add the experimental flag in your Astro config and remove rawEnvValues if it was enabled:

    // astro.config.mjs
    import { defineConfig } from "astro/config";
    
    export default defineConfig({
    +  experimental: {
    +    staticImportMetaEnv: true
    -    rawEnvValues: false
    +  }
    });
    

    Updating your project

    If you were relying on Astro's default coercion, you may need to update your project code to apply it manually:

    // src/components/MyComponent.astro
    - const enabled: boolean = import.meta.env.ENABLED;
    + const enabled: boolean = import.meta.env.ENABLED === "true";
    

    If you were relying on the transformation into process.env calls, you may need to update your project code to apply it manually:

    // src/components/MyComponent.astro
    - const enabled: boolean = import.meta.env.DB_PASSWORD;
    + const enabled: boolean = process.env.DB_PASSWORD;
    

    You may also need to update types:

    // src/env.d.ts
    interface ImportMetaEnv {
      readonly PUBLIC_POKEAPI: string;
    -  readonly DB_PASSWORD: string;
    -  readonly ENABLED: boolean;
    +  readonly ENABLED: string;
    }
    
    interface ImportMeta {
      readonly env: ImportMetaEnv;
    }
    
    + namespace NodeJS {
    +  interface ProcessEnv {
    +    DB_PASSWORD: string;
    +  }
    + }
    

    See the experimental static import.meta.env documentation for more information about this feature. You can learn more about using environment variables in Astro, including astro:env, in the environment variables documentation.

  • #14122 41ed3ac Thanks @ascorbic! - Adds experimental support for automatic Chrome DevTools workspace folders

    This feature allows you to edit files directly in the browser and have those changes reflected in your local file system via a connected workspace folder. This allows you to apply edits such as CSS tweaks without leaving your browser tab!

    With this feature enabled, the Astro dev server will automatically configure a Chrome DevTools workspace for your project. Your project will then appear as a workspace source, ready to connect. Then, changes that you make in the "Sources" panel are automatically saved to your project source code.

    To enable this feature, add the experimental flag chromeDevtoolsWorkspace to your Astro config:

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

    See the experimental Chrome DevTools workspace feature documentation for more information.

5.12.9

Patch Changes

  • #14020 9518975 Thanks @jp-knj and @asieradzk! - Prevent double-prefixed redirect paths when using fallback and redirectToDefaultLocale together

    Fixes an issue where i18n fallback routes would generate double-prefixed paths (e.g., /es/es/test/item1/) when fallback and redirectToDefaultLocale configurations were used together. The fix adds proper checks to prevent double prefixing in route generation.

  • #14199 3e4cb8e Thanks @ascorbic! - Fixes a bug that prevented HMR from working with inline styles

5.12.8

Patch Changes

  • 0567fb7 Thanks @ascorbic! - Adds // to list of internal path prefixes that do not have automated trailing slash handling

  • #13894 b36e72f Thanks @florian-lefebvre! - Removes Astro Studio commands from the CLI help

  • Updated dependencies [0567fb7]:

    • @astrojs/internal-helpers@0.7.1
    • @astrojs/markdown-remark@6.3.5

5.12.7

Patch Changes

  • #14169 f4e8889 Thanks @ascorbic! - Skips trailing slash handling for paths that start with /..

  • #14170 34e6b3a Thanks @ematipico! - Fixes an issue where static redirects couldn't correctly generate a redirect when the destination is a prerendered route, and the output is set to "server".

  • #14169 f4e8889 Thanks @ascorbic! - Fixes a bug that prevented images from being displayed in dev when using the Netlify adapter with trailingSlash set to always

  • Updated dependencies [f4e8889]:

    • @astrojs/internal-helpers@0.7.0
    • @astrojs/markdown-remark@6.3.4

5.12.6

Patch Changes

  • #14153 29e9283 Thanks @jp-knj! - Fixes a regression introduced by a recent optimisation of how SVG images are emitted during the build.

  • #14156 592f08d Thanks @TheOtterlord! - Fix the client router not submitting forms if the active URL contained a hash

  • #14160 d2e25c6 Thanks @ascorbic! - Fixes a bug that meant some remote image URLs could cause invalid filenames to be used for processed images

  • #14167 62bd071 Thanks @ascorbic! - Fixes a bug that prevented destroyed sessions from being deleted from storage unless the session had been loaded

5.12.5

Patch Changes

  • #14059 19f53eb Thanks @benosmac! - Fixes a bug in i18n implementation, where Astro didn't emit the correct pages when fallback is enabled, and a locale uses a catch-all route, e.g. src/pages/es/[...catchAll].astro

  • #14155 31822c3 Thanks @ascorbic! - Fixes a bug that caused an error "serverEntrypointModule[_start] is not a function" in some adapters

5.12.4

Patch Changes

  • #14031 e9206c1 Thanks @jp-knj! - Optimized the build pipeline for SVG images. Now, Astro doesn't reprocess images that have already been processed.

  • #14132 976879a Thanks @ematipico! - Fixes a bug where the property Astro.routePattern/context.routePattern wasn't updated when using a rewrite via middleware.

  • #14131 aafc4d7 Thanks @florian-lefebvre! - Fixes a case where an error occurring in a middleware would show the dev overlay instead of the custom 500.astro page

  • #14127 2309ada Thanks @florian-lefebvre! - Upgrades zod

  • #14134 186c201 Thanks @ascorbic! - Throws a more helpful error in dev if trying to use a server island without an adapter

  • #14129 3572d85 Thanks @ematipico! - Fixes a bug where the CSP headers was incorrectly added to a page when using an adapter.

5.12.3

Patch Changes

  • #14119 14807a4 Thanks @ascorbic! - Fixes a bug that caused builds to fail if a client directive was mistakenly added to an Astro component

  • #14001 4b03d9c Thanks @dnek! - Fixes an issue where getImage() assigned the resized base URL to the srcset URL of ImageTransform, which matched the width, height, and format of the original image.

5.12.2

Patch Changes

5.12.1

Patch Changes

5.12.0

Minor Changes

  • #13971 fe35ee2 Thanks @adamhl8! - Adds an experimental flag rawEnvValues to disable coercion of import.meta.env values (e.g. converting strings to other data types) that are populated from process.env

    Astro allows you to configure a type-safe schema for your environment variables, and converts variables imported via astro:env into the expected type.

    However, Astro also converts your environment variables used through import.meta.env in some cases, and this can prevent access to some values such as the strings "true" (which is converted to a boolean value), and "1" (which is converted to a number).

    The experimental.rawEnvValues flag disables coercion of import.meta.env values that are populated from process.env, allowing you to use the raw value.

    To enable this feature, add the experimental flag in your Astro config:

    import { defineConfig } from "astro/config"
    
    export default defineConfig({
    +  experimental: {
    +    rawEnvValues: true,
    +  }
    })
    

    If you were relying on this coercion, you may need to update your project code to apply it manually:

    - const enabled: boolean = import.meta.env.ENABLED
    + const enabled: boolean = import.meta.env.ENABLED === "true"
    

    See the experimental raw environment variables reference docs for more information.

  • #13941 6bd5f75 Thanks @aditsachde! - Adds support for TOML files to Astro's built-in glob() and file() content loaders.

    In Astro 5.2, Astro added support for using TOML frontmatter in Markdown files instead of YAML. However, if you wanted to use TOML files as local content collection entries themselves, you needed to write your own loader.

    Astro 5.12 now directly supports loading data from TOML files in content collections in both the glob() and the file() loaders.

    If you had added your own TOML content parser for the file() loader, you can now remove it as this functionality is now included:

    // src/content.config.ts
    import { defineCollection } from "astro:content";
    import { file } from "astro/loaders";
    - import { parse as parseToml } from "toml";
    const dogs = defineCollection({
    -  loader: file("src/data/dogs.toml", { parser: (text) => parseToml(text) }),
    + loader: file("src/data/dogs.toml")
      schema: /* ... */
    })
    

    Note that TOML does not support top-level arrays. Instead, the file() loader considers each top-level table to be an independent entry. The table header is populated in the id field of the entry object.

    See Astro's content collections guide for more information on using the built-in content loaders.

Patch Changes

  • Updated dependencies [6bd5f75]:
    • @astrojs/markdown-remark@6.3.3

5.11.2

Patch Changes

  • #14064 2eb77d8 Thanks @jp-knj! - Allows using tsconfig compilerOptions.paths without setting compilerOptions.baseUrl

  • #14068 10189c0 Thanks @jsparkdev! - Fixes the incorrect CSS import path shown in the terminal message during Tailwind integration setup.

5.11.1

Patch Changes

  • #14045 3276b79 Thanks @ghubo! - Fixes a problem where importing animated .avif files returns a NoImageMetadata error.

  • #14041 0c4d5f8 Thanks @dixslyf! - Fixes a <ClientRouter /> bug where the fallback view transition animations when exiting a page ran too early for browsers that do not support the View Transition API. This bug prevented event.viewTransition?.skipTransition() from skipping the page exit animation when used in an astro:before-swap event hook.

5.11.0

Minor Changes

  • #13972 db8f8be Thanks @ematipico! - Updates the NodeApp.match() function in the Adapter API to accept a second, optional parameter to allow adapter authors to add headers to static, prerendered pages.

    NodeApp.match(request) currently checks whether there is a route that matches the given Request. If there is a prerendered route, the function returns undefined, because static routes are already rendered and their headers cannot be updated.

    When the new, optional boolean parameter is passed (e.g. NodeApp.match(request, true)), Astro will return the first matched route, even when it's a prerendered route. This allows your adapter to now access static routes and provides the opportunity to set headers for these pages, for example, to implement a Content Security Policy (CSP).

Patch Changes

  • #14029 42562f9 Thanks @ematipico! - Fixes a bug where server islands wouldn't be correctly rendered when they are rendered inside fragments.

    Now the following examples work as expected:

    ---
    import { Cart } from '../components/Cart.astro';
    ---
    
    <>
      <Cart server:defer />
    </>
    
    <Fragment slot="rest">
      <Cart server:defer>
        <div slot="fallback">Not working</div>
      </Cart>
    </Fragment>
    
  • #14017 8d238bc Thanks @dmgawel! - Fixes a bug where i18n fallback rewrites didn't work in dynamic pages.

5.10.2

Patch Changes

  • #14000 3cbedae Thanks @feelixe! - Fix routePattern JSDoc examples to show correct return values

  • #13990 de6cfd6 Thanks @isVivek99! - Fixes a case where astro:config/client and astro:config/server virtual modules would not contain config passed to integrations updateConfig() during the build

  • #14019 a160d1e Thanks @ascorbic! - Removes the requirement to set type: 'live' when defining experimental live content collections

    Previously, live collections required a type and loader configured. Now, Astro can determine that your collection is a live collection without defining it explicitly.

    This means it is now safe to remove type: 'live' from your collections defined in src/live.config.ts:

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

    This is not a breaking change: your existing live collections will continue to work even if you still include type: 'live'. However, we suggest removing this line at your earliest convenience for future compatibility when the feature becomes stable and this config option may be removed entirely.

  • #13966 598da21 Thanks @msamoylov! - Fixes a broken link on the default 404 page in development

5.10.1

Patch Changes

  • #13988 609044c Thanks @ascorbic! - Fixes a bug in live collections that caused it to incorrectly complain about the collection being defined in the wrong file

  • #13909 b258d86 Thanks @isVivek99! - Fixes rendering of special boolean attributes for custom elements

  • #13983 e718375 Thanks @florian-lefebvre! - Fixes a case where the toolbar audit would incorrectly flag images processed by Astro in content collections documents

  • #13999 f077b68 Thanks @ascorbic! - Adds lastModified field to experimental live collection cache hints

    Live loaders can now set a lastModified field in the cache hints for entries and collections to indicate when the data was last modified. This is then available in the cacheHint field returned by getCollection and getEntry.

  • #13987 08f34b1 Thanks @ematipico! - Adds an informative message in dev mode when the CSP feature is enabled.

  • #14005 82aad62 Thanks @ematipico! - Fixes a bug where inline styles and scripts didn't work when CSP was enabled. Now when adding <styles> elements inside an Astro component, their hashes care correctly computed.

  • #13985 0b4c641 Thanks @jsparkdev! - Updates wrong link

5.10.0

Minor Changes

  • #13917 e615216 Thanks @ascorbic! - Adds a new priority attribute for Astro's image components.

    This change introduces a new priority option for the <Image /> and <Picture /> components, which automatically sets the loading, decoding, and fetchpriority attributes to their optimal values for above-the-fold images which should be loaded immediately.

    It is a boolean prop, and you can use the shorthand syntax by simply adding priority as a prop to the <Image /> or <Picture /> component. When set, it will apply the following attributes:

    • loading="eager"
    • decoding="sync"
    • fetchpriority="high"

    The individual attributes can still be set manually if you need to customize your images further.

    By default, the Astro <Image /> component generates <img> tags that lazy-load their content by setting loading="lazy" and decoding="async". This improves performance by deferring the loading of images that are not immediately visible in the viewport, and gives the best scores in performance audits like Lighthouse.

    The new priority attribute will override those defaults and automatically add the best settings for your high-priority assets.

    This option was previously available for experimental responsive images, but now it is a standard feature for all images.

    Usage

    <Image src="/path/to/image.jpg" alt="An example image" priority />
    

    Note

    You should only use the priority option for images that are critical to the initial rendering of the page, and ideally only one image per page. This is often an image identified as the LCP element when running Lighthouse tests. Using it for too many images will lead to performance issues, as it forces the browser to load those images immediately, potentially blocking the rendering of other content.

  • #13917 e615216 Thanks @ascorbic! - The responsive images feature introduced behind a flag in v5.0.0 is no longer experimental and is available for general use.

    The new responsive images feature in Astro automatically generates optimized images for different screen sizes and resolutions, and applies the correct attributes to ensure that images are displayed correctly on all devices.

    Enable the image.responsiveStyles option in your Astro config. Then, set a layout attribute on any or component, or configure a default image.layout, for instantly responsive images with automatically generated srcset and sizes attributes based on the image's dimensions and the layout type.

    Displaying images correctly on the web can be challenging, and is one of the most common performance issues seen in sites. This new feature simplifies the most challenging part of the process: serving your site visitor an image optimized for their viewing experience, and for your website's performance.

    For full details, see the updated Image guide.

    Migration from Experimental Responsive Images

    The experimental.responsiveImages flag has been removed, and all experimental image configuration options have been renamed to their final names.

    If you were using the experimental responsive images feature, you'll need to update your configuration:

    Remove the experimental flag
    export default defineConfig({
       experimental: {
    -    responsiveImages: true,
       },
    });
    
    Update image configuration options

    During the experimental phase, default styles were applied automatically to responsive images. Now, you need to explicitly set the responsiveStyles option to true if you want these styles applied.

    export default defineConfig({
      image: {
    +    responsiveStyles: true,
      },
    });
    

    The experimental image configuration options have been renamed:

    Before:

    export default defineConfig({
      image: {
        experimentalLayout: 'constrained',
        experimentalObjectFit: 'cover',
        experimentalObjectPosition: 'center',
        experimentalBreakpoints: [640, 750, 828, 1080, 1280],
        experimentalDefaultStyles: true,
      },
      experimental: {
        responsiveImages: true,
      },
    });
    

    After:

    export default defineConfig({
      image: {
        layout: 'constrained',
        objectFit: 'cover',
        objectPosition: 'center',
        breakpoints: [640, 750, 828, 1080, 1280],
        responsiveStyles: true, // This is now *false* by default
      },
    });
    
    Component usage remains the same

    The layout, fit, and position props on <Image> and <Picture> components work exactly the same as before:

    <Image
      src={myImage}
      alt="A responsive image"
      layout="constrained"
      fit="cover"
      position="center"
    />
    

    If you weren't using the experimental responsive images feature, no changes are required.

    Please see the Image guide for more information on using responsive images in Astro.

  • #13685 3c04c1f Thanks @ascorbic! - Adds experimental support for live content collections

    Live content collections are a new type of content collection that fetch their data at runtime rather than build time. This allows you to access frequently-updated data from CMSs, APIs, databases, or other sources using a unified API, without needing to rebuild your site when the data changes.

    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 is no method for updating the data store between builds, meaning any updates to the data need a full site deploy, even if the pages are rendered on-demand. This means that content collections are not suitable for pages that update frequently. Instead, today these pages tend to access the APIs directly in the frontmatter. This works, but leads to a lot of boilerplate, and means users don't benefit from the simple, unified API that content loaders offer. In most cases users tend to individually create loader libraries that they share between pages.

    Live content collections solve this problem by allowing you to create loaders that fetch data at runtime, rather than build time. This means that the data is always up-to-date, without needing to rebuild the site.

    How to use

    To enable live collections add the experimental.liveContentCollections flag to your astro.config.mjs file:

    {
      experimental: {
        liveContentCollections: true,
      },
    }
    

    Then create a new src/live.config.ts file (alongside your src/content.config.ts if you have one) to define your live collections with a live loader and optionally a schema using the new defineLiveCollection() function from the astro:content module.

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

    You can then use the dedicated getLiveCollection() and getLiveEntry() functions to access your 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.title}</h1>
    <Content />
    

    See the docs for the experimental live content collections feature for more details on how to use this feature, including how to create a live loader. Please give feedback on the RFC PR if you have any suggestions or issues.

Patch Changes

  • #13957 304df34 Thanks @ematipico! - Fixes an issue where report-uri wasn't available in experimental.csp.directives, causing a typing error and a runtime validation error.

  • #13957 304df34 Thanks @ematipico! - Fixes a type error for the CSP directives upgrade-insecure-requests, sandbox, and trusted-type.

  • #13862 fe8f61a Thanks @florian-lefebvre! - Fixes a case where the dev toolbar would crash if it could not retrieve some essential data

  • #13976 0a31d99 Thanks @florian-lefebvre! - Fixes a case where Astro Actions types would be broken when using a tsconfig.json with "moduleResolution": "nodenext"

5.9.4

Patch Changes

  • #13951 7eb88f1 Thanks @ascorbic! - Fixes a issue that caused errors when using an adapter-provided session driver with custom options

  • #13953 448bddc Thanks @zaitovalisher! - Fixes a bug where quotes were not added to the 'strict-dynamic' CSP directive

5.9.3

Patch Changes

  • #13923 a9ac5ed Thanks @ematipico! - BREAKING CHANGE to the experimental Content Security Policy (CSP) only

    Changes the behavior of experimental Content Security Policy (CSP) to now serve hashes differently depending on whether or not a page is prerendered:

    • Via the <meta> element for static pages.
    • Via the Response header content-security-policy for on-demand rendered pages.

    This new strategy allows you to add CSP content that is not supported in a <meta> element (e.g. report-uri, frame-ancestors, and sandbox directives) to on-demand rendered pages.

    No change to your project code is required as this is an implementation detail. However, this will result in a different HTML output for pages that are rendered on demand. Please check your production site to verify that CSP is working as intended.

    To keep up to date with this developing feature, or to leave feedback, visit the CSP Roadmap proposal.

  • #13926 953a249 Thanks @ematipico! - Adds a new Astro Adapter Feature called experimentalStaticHeaders to allow your adapter to receive the Headers for rendered static pages.

    Adapters that enable support for this feature can access header values directly, affecting their handling of some Astro features such as Content Security Policy (CSP). For example, Astro will no longer serve the CSP <meta http-equiv="content-security-policy"> element in static pages to adapters with this support.

    Astro will serve the value of the header inside a map that can be retrieved from the hook astro:build:generated. Adapters can read this mapping and use their hosting headers capabilities to create a configuration file.

    A new field called experimentalRouteToHeaders will contain a map of Map<IntegrationResolvedRoute, Headers> where the Headers type contains the headers emitted by the rendered static route.

    To enable support for this experimental Astro Adapter Feature, add it to your adapterFeatures in your adapter config:

    // my-adapter.mjs
    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: {
                experimentalStaticHeaders: true,
              },
            });
          },
        },
      };
    }
    

    See the Adapter API docs for more information about providing adapter features.

  • #13697 af83b85 Thanks @benosmac! - Fixes issues with fallback route pattern matching when i18n.routing.fallbackType is rewrite.

    • Adds conditions for route matching in generatePath when building fallback routes and checking for existing translated pages

    Now for a route to be matched it needs to be inside a named [locale] folder. This fixes an issue where route.pattern.test() incorrectly matched dynamic routes, causing the page to be skipped.

    • Adds conditions for route matching in findRouteToRewrite

    Now the requested pathname must exist in route.distURL for a dynamic route to match. This fixes an issue where route.pattern.test() incorrectly matched dynamic routes, causing the build to fail.

  • #13924 1cd8c3b Thanks @qw-in! - Fixes an edge case where isPrerendered was incorrectly set to false for static redirects.

  • #13926 953a249 Thanks @ematipico! - Fixes an issue where the experimental CSP meta element wasn't placed in the <head> element as early as possible, causing these policies to not apply to styles and scripts that came before the meta element.

5.9.2

Patch Changes

  • #13919 423fe60 Thanks @ematipico! - Fixes a bug where Astro added quotes to the CSP resources.

    Only certain resources require quotes (e.g. 'self' but not https://cdn.example.com), so Astro no longer adds quotes to any resources. You must now provide the quotes yourself for resources such as 'self' when necessary:

    export default defineConfig({
      experimental: {
        csp: {
          styleDirective: {
            resources: [
    -          "self",
    +          "'self'",
              "https://cdn.example.com"
            ]
          }
        }
      }
    })
    
  • #13914 76c5480 Thanks @ematipico! - BREAKING CHANGE to the experimental Content Security Policy feature only

    Removes support for experimental Content Security Policy (CSP) when using the <ClientRouter /> component for view transitions.

    It is no longer possible to enable experimental CSP while using Astro's view transitions. Support was already unstable with the <ClientRouter /> because CSP required making its underlying implementation asynchronous. This caused breaking changes for several users and therefore, this PR removes support completely.

    If you are currently using the component for view transitions, please remove the experimental CSP flag as they cannot be used together.

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

    Alternatively, to continue using experimental CSP in your project, you can consider migrating to the browser native View Transition API and remove the <ClientRouter /> from your project. You may be able to achieve similar results if you are not using Astro's enhancements to the native View Transitions and Navigation APIs.

    Support might be reintroduced in future releases. You can follow this experimental feature's development in the CSP RFC.

5.9.1

Patch Changes

5.9.0

Minor Changes

  • #13802 0eafe14 Thanks @ematipico! - Adds experimental Content Security Policy (CSP) support

    CSP is an important feature to provide fine-grained control over resources that can or cannot be downloaded and executed by a document. In particular, it can help protect against cross-site scripting (XSS) attacks.

    Enabling this feature adds additional security to Astro's handling of processed and bundled scripts and styles by default, and allows you to further configure these, and additional, content types. This new experimental feature has been designed to work in every Astro rendering environment (static pages, dynamic pages and single page applications), while giving you maximum flexibility and with type-safety in mind.

    It is compatible with most of Astro's features such as client islands, and server islands, although Astro's view transitions using the <ClientRouter /> are not yet fully supported. Inline scripts are not supported out of the box, but you can provide your own hashes for external and inline scripts.

    To enable this feature, add the experimental flag in your Astro config:

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

    For more information on enabling and using this feature in your project, see the Experimental CSP docs.

    For a complete overview, and to give feedback on this experimental API, see the Content Security Policy RFC.

  • #13850 1766d22 Thanks @ascorbic! - Provides a Markdown renderer to content loaders

    When creating a content loader, you will now have access to a renderMarkdown function that allows you to render Markdown content directly within your loaders. It uses the same settings and plugins as the renderer used for Markdown files in Astro, and follows any Markdown settings you have configured in your Astro project.

    This allows you to render Markdown content from various sources, such as a CMS or other data sources, directly in your loaders without needing to preprocess the Markdown content separately.

    import type { Loader } from 'astro/loaders';
    import { loadFromCMS } from './cms';
    
    export function myLoader(settings): Loader {
      return {
        name: 'my-loader',
        async load({ renderMarkdown, store }) {
          const entries = await loadFromCMS();
    
          store.clear();
    
          for (const entry of entries) {
            // Assume each entry has a 'content' field with markdown content
            store.set({
              id: entry.id,
              data: entry,
              rendered: await renderMarkdown(entry.content),
            });
          }
        },
      };
    }
    

    The return value of renderMarkdown is an object with two properties: html and metadata. These match the rendered property of content entries in content collections, so you can use them to render the content in your components or pages.

    ---
    import { getEntry, render } from 'astro:content';
    const entry = await getEntry('my-collection', Astro.params.id);
    const { Content } = await render(entry);
    ---
    
    <Content />
    

    For more information, see the Content Loader API docs.

  • #13887 62f0668 Thanks @yanthomasdev! - Adds an option for integration authors to suppress adapter warning/errors in supportedAstroFeatures. This is useful when either an warning/error isn't applicable in a specific context or the default one might conflict and confuse users.

    To do so, you can add suppress: "all" (to suppress both the default and custom message) or suppress: "default" (to only suppress the default one):

    setAdapter({
      name: 'my-astro-integration',
      supportedAstroFeatures: {
        staticOutput: 'stable',
        hybridOutput: 'stable',
        sharpImageService: {
          support: 'limited',
          message:
            "The sharp image service isn't available in the deploy environment, but will be used by prerendered pages on build.",
          suppress: 'default',
        },
      },
    });
    

    For more information, see the Adapter API reference docs.

5.8.2

Patch Changes

5.8.1

Patch Changes

  • #13037 de2fc9b Thanks @nanarino! - Fixes rendering of the popover attribute when it has a boolean value

  • #13851 45ae95a Thanks @ascorbic! - Allows disabling default styles for responsive images

    This change adds a new image.experimentalDefaultStyles option that allows you to disable the default styles applied to responsive images.

    When using experimental responsive images, Astro applies default styles to ensure the images resize correctly. In most cases this is what you want and they are applied with low specificity so your own styles override them. However in some cases you may want to disable these default styles entirely. This is particularly useful when using Tailwind 4, because it uses CSS cascade layers to apply styles, making it difficult to override the default styles.

    image.experimentalDefaultStyles is a boolean option that defaults to true, so you can change it in your Astro config file like this:

    export default {
      image: {
        experimentalDefaultStyles: false,
      },
      experimental: {
        responsiveImages: true,
      },
    };
    
  • #13858 cb1a168 Thanks @florian-lefebvre! - Fixes the warning shown when client directives are used on Astro components

  • #12574 da266d0 Thanks @apatel369! - Allows using server islands in mdx files

  • #13843 fbcfa68 Thanks @z1haze! - Export type AstroSession to allow use in explicitly typed safe code.

5.8.0

Minor Changes

  • #13809 3c3b492 Thanks @ascorbic! - Increases minimum Node.js version to 18.20.8

    Node.js 18 has now reached end-of-life and should not be used. For now, Astro will continue to support Node.js 18.20.8, which is the final LTS release of Node.js 18, as well as Node.js 20 and Node.js 22 or later. We will drop support for Node.js 18 in a future release, so we recommend upgrading to Node.js 22 as soon as possible. See Astro's Node.js support policy for more details.

    ⚠️ Important note for users of Cloudflare Pages: The current build image for Cloudflare Pages uses Node.js 18.17.1 by default, which is no longer supported by Astro. If you are using Cloudflare Pages you should override the default Node.js version to Node.js 22. This does not affect users of Cloudflare Workers, which uses Node.js 22 by default.

Patch Changes

  • Updated dependencies [3c3b492]:
    • @astrojs/telemetry@3.3.0
    • @astrojs/markdown-remark@6.3.2

5.7.14

Patch Changes

  • #13773 3aa5337 Thanks @sijad! - Ignores lightningcss unsupported pseudo-class warning.

  • #13833 5a6d2ae Thanks @ascorbic! - Fixes an issue where session modules would fail to resolve in Node.js < 20.6

  • #13383 f7f712c Thanks @Haberkamp! - Stop toolbar settings from overflowing

  • #13794 85b19d8 Thanks @alexcarpenter! - Exclude pre tags from a11y-no-noninteractive-tabindex audit check.

  • #13373 50ef568 Thanks @jpwienekus! - Fixes a bug where highlights and tooltips render over the audit list window.

  • #13769 e9fc456 Thanks @romanstetsyk! - Expand ActionError codes to include all IANA-registered HTTP error codes.

  • #13668 866285a Thanks @sapphi-red! - Replaces internal CSS chunking behavior for Astro components' scoped styles to use Vite's cssScopeTo feature. The feature is a port of Astro's implementation so this should not change the behavior.

5.7.13

Patch Changes

  • #13761 a2e8463 Thanks @jp-knj! - Adds new content collections errors

  • #13788 7d0b7ac Thanks @florian-lefebvre! - Fixes a case where an error would not be thrown when using the <Font /> component from the experimental fonts API without adding fonts in the Astro config

  • #13784 d7a1889 Thanks @florian-lefebvre! - Fixes the experimental fonts API to correctly take config.base, config.build.assets and config.build.assetsPrefix into account

  • #13777 a56b8ea Thanks @L4Ph! - Fixed an issue where looping GIF animation would stop when converted to WebP

  • #13566 0489d8f Thanks @TheOtterlord! - Fix build errors being ignored when build.concurrency > 1

5.7.12

Patch Changes

  • #13752 a079c21 Thanks @florian-lefebvre! - Improves handling of font URLs not ending with a file extension when using the experimental fonts API

  • #13750 7d3127d Thanks @martrapp! - Allows the ClientRouter to open new tabs or windows when submitting forms by clicking while holding the Cmd, Ctrl, or Shift key.

  • #13765 d874fe0 Thanks @florian-lefebvre! - Fixes a case where font sources with relative protocol URLs would fail when using the experimental fonts API

  • #13640 5e582e7 Thanks @florian-lefebvre! - Allows inferring weight and style when using the local provider of the experimental fonts API

    If you want Astro to infer those properties directly from your local font files, leave them undefined:

    {
      // No weight specified: infer
      style: 'normal'; // Do not infer
    }
    

5.7.11

Patch Changes

5.7.10

Patch Changes

5.7.9

Patch Changes

5.7.8

Patch Changes

  • #13715 b32dffa Thanks @florian-lefebvre! - Updates unifont to fix a case where a unicodeRange related error would be thrown when using the experimental fonts API

5.7.7

Patch Changes

  • #13705 28f8716 Thanks @florian-lefebvre! - Updates unifont to latest and adds support for fetch options from remote providers when using the experimental fonts API

  • #13692 60d5be4 Thanks @Le0Developer! - Fixes a bug where Astro couldn't probably use inferSize for images that contain apostrophe ' in their name.

  • #13698 ab98f88 Thanks @sarah11918! - Improves the configuration reference docs for the adapter entry with more relevant text and links.

  • #13706 b4929ae Thanks @ascorbic! - Fixes typechecking for content config schema

  • #13653 a7b2dc6 Thanks @florian-lefebvre! - Reduces the amount of preloaded files for the local provider when using the experimental fonts API

  • #13653 a7b2dc6 Thanks @florian-lefebvre! - Fixes a case where invalid CSS was emitted when using an experimental fonts API family name containing a space

5.7.6

Patch Changes

  • #13703 659904b Thanks @ascorbic! - Fixes a bug where empty fallbacks could not be provided when using the experimental fonts API

  • #13680 18e1b97 Thanks @florian-lefebvre! - Improves the UnsupportedExternalRedirect error message to include more details such as the concerned destination

  • #13703 659904b Thanks @ascorbic! - Simplifies styles for experimental responsive images

    ⚠️ BREAKING CHANGE FOR EXPERIMENTAL RESPONSIVE IMAGES ONLY ⚠️

    The generated styles for image layouts are now simpler and easier to override. Previously the responsive image component used CSS to set the size and aspect ratio of the images, but this is no longer needed. Now the styles just include object-fit and object-position for all images, and sets max-width: 100% for constrained images and width: 100% for full-width images.

    This is an implementation change only, and most users will see no change. However, it may affect any custom styles you have added to your responsive images. Please check your rendered images to determine whether any change to your CSS is needed.

    The styles now use the :where() pseudo-class, which has a specificity of 0, meaning that it is easy to override with your own styles. You can now be sure that your own classes will always override the applied styles, as will global styles on img.

    An exception is Tailwind 4, which uses cascade layers, meaning the rules are always lower specificity. Astro supports browsers that do not support cascade layers, so we cannot use this. If you need to override the styles using Tailwind 4, you must use !important classes. Do check if this is needed though: there may be a layout that is more appropriate for your use case.

  • #13703 659904b Thanks @ascorbic! - Adds warnings about using local font files in the publicDir when the experimental fonts API is enabled.

  • #13703 659904b Thanks @ascorbic! - Renames experimental responsive image layout option from "responsive" to "constrained"

    ⚠️ BREAKING CHANGE FOR EXPERIMENTAL RESPONSIVE IMAGES ONLY ⚠️

    The layout option called "responsive" is renamed to "constrained" to better reflect its behavior.

    The previous name was causing confusion, because it is also the name of the feature. The responsive layout option is specifically for images that are displayed at the requested size, unless they do not fit the width of their container, at which point they would be scaled down to fit. They do not get scaled beyond the intrinsic size of the source image, or the width prop if provided.

    It became clear from user feedback that many people (understandably) thought that they needed to set layout to responsive if they wanted to use responsive images. They then struggled with overriding styles to make the image scale up for full-width hero images, for example, when they should have been using full-width layout. Renaming the layout to constrained should make it clearer that this layout is for when you want to constrain the maximum size of the image, but allow it to scale-down.

    Upgrading

    If you set a default image.experimentalLayout in your astro.config.mjs, or set it on a per-image basis using the layout prop, you will need to change all occurences to constrained:

    // astro.config.mjs
    export default {
      image: {
    -    experimentalLayout: 'responsive',
    +    experimentalLayout: 'constrained',
      },
    }
    
    // src/pages/index.astro
    ---
    import { Image } from 'astro:assets';
    ---
    - <Image src="/image.jpg" layout="responsive" />
    + <Image src="/image.jpg" layout="constrained" />
    

    Please give feedback on the RFC if you have any questions or comments about the responsive images API.

5.7.5

Patch Changes

5.7.4

Patch Changes

5.7.3

Patch Changes

  • #13643 67b7493 Thanks @tanishqmanuja! - Fixes a case where the font face src format would be invalid when using the experimental fonts API

  • #13639 23410c6 Thanks @florian-lefebvre! - Fixes a case where some font families would not be downloaded when using the same font provider several times, using the experimental fonts API

5.7.2

Patch Changes

5.7.1

Patch Changes

5.7.0

Minor Changes

  • #13527 2fd6a6b Thanks @ascorbic! - The experimental session API introduced in Astro 5.1 is now stable and ready for production use.

    Sessions are used to store user state between requests for on-demand rendered pages. You can use them to store user data, such as authentication tokens, shopping cart contents, or any other data that needs to persist across requests:

    ---
    export const prerender = false; // Not needed with 'server' output
    const cart = await Astro.session.get('cart');
    ---
    
    <a href="/checkout">🛒 {cart?.length ?? 0} items</a>
    

    Configuring session storage

    Sessions require a storage driver to store the data. The Node, Cloudflare and Netlify adapters automatically configure a default driver for you, but other adapters currently require you to specify a custom storage driver in your configuration.

    If you are using an adapter that doesn't have a default driver, or if you want to choose a different driver, you can configure it using the session configuration option:

    import { defineConfig } from 'astro/config';
    import vercel from '@astrojs/vercel';
    
    export default defineConfig({
      adapter: vercel(),
      session: {
        driver: 'upstash',
      },
    });
    

    Using sessions

    Sessions are available in on-demand rendered pages, API endpoints, actions and middleware.

    In pages and components, you can access the session using Astro.session:

    ---
    const cart = await Astro.session.get('cart');
    ---
    
    <a href="/checkout">🛒 {cart?.length ?? 0} items</a>
    

    In endpoints, actions, and middleware, you can access the session using context.session:

    export async function GET(context) {
      const cart = await context.session.get('cart');
      return Response.json({ cart });
    }
    

    If you attempt to access the session when there is no storage driver configured, or in a prerendered page, the session object will be undefined and an error will be logged in the console:

    ---
    export const prerender = true;
    const cart = await Astro.session?.get('cart'); // Logs an error. Astro.session is undefined
    ---
    

    Upgrading from Experimental to Stable

    If you were previously using the experimental API, please remove the experimental.session flag from your configuration:

    import { defineConfig } from 'astro/config';
    import node from '@astrojs/node';
    
    export default defineConfig({
       adapter: node({
         mode: "standalone",
       }),
    -  experimental: {
    -    session: true,
    -  },
    });
    

    See the sessions guide for more information.

  • #12775 b1fe521 Thanks @florian-lefebvre! - Adds a new, experimental Fonts API to provide first-party support for fonts in Astro.

    This experimental feature allows you to use fonts from both your file system and several built-in supported providers (e.g. Google, Fontsource, Bunny) through a unified API. Keep your site performant thanks to sensible defaults and automatic optimizations including fallback font generation.

    To enable this feature, configure an experimental.fonts object with one or more fonts:

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

    Then, add a <Font /> component and site-wide styling in your <head>:

    ---
    import { Font } from 'astro:assets';
    ---
    
    <Font cssVariable="--font-roboto" preload />
    <style>
      body {
        font-family: var(--font-roboto);
      }
    </style>
    

    Visit the experimental Fonts documentation for the full API, how to get started, and even how to build your own custom AstroFontProvider if we don't yet support your preferred font service.

    For a complete overview, and to give feedback on this experimental API, see the Fonts RFC and help shape its future.

  • #13560 df3fd54 Thanks @ematipico! - The virtual module astro:config introduced behind a flag in v5.2.0 is no longer experimental and is available for general use.

    This virtual module exposes two sub-paths for type-safe, controlled access to your configuration:

    • astro:config/client: exposes config information that is safe to expose to the client.
    • astro:config/server: exposes additional information that is safe to expose to the server, such as file and directory paths.

    Access these in any file inside your project to import and use select values from your Astro config:

    // src/utils.js
    import { trailingSlash } from 'astro:config/client';
    
    function addForwardSlash(path) {
      if (trailingSlash === 'always') {
        return path.endsWith('/') ? path : path + '/';
      } else {
        return path;
      }
    }
    

    If you were previously using this feature, please remove the experimental flag from your Astro config:

    // astro.config.mjs
    export default defineConfig({
    -  experimental: {
    -    serializeConfig: true
    -  }
    })
    

    If you have been waiting for feature stabilization before using configuration imports, you can now do so.

    Please see the astro:config reference for more about this feature.

  • #13578 406501a Thanks @stramel! - The SVG import feature introduced behind a flag in v5.0.0 is no longer experimental and is available for general use.

    This feature allows you to import SVG files directly into your Astro project as components and inline them into your HTML.

    To use this feature, import an SVG file in your Astro project, passing any common SVG attributes to the imported component.

    ---
    import Logo from './path/to/svg/file.svg';
    ---
    
    <Logo width={64} height={64} fill="currentColor" />
    

    If you have been waiting for stabilization before using the SVG Components feature, you can now do so.

    If you were previously using this feature, please remove the experimental flag from your Astro config:

    import { defineConfig } from 'astro'
    
    export default defineConfig({
    -  experimental: {
    -    svg: true,
    -  }
    })
    

    Additionally, a few features that were available during the experimental stage were removed in a previous release. Please see the v5.6.0 changelog for details if you have not yet already updated your project code for the experimental feature accordingly.

    Please see the SVG Components guide in docs for more about this feature.

Patch Changes

  • #13602 3213450 Thanks @natemoo-re! - Updates the Audit dev toolbar app to automatically strip data-astro-source-file and data-astro-source-loc attributes in dev mode.

  • #13598 f5de51e Thanks @dreyfus92! - Fix routing with base paths when trailingSlash is set to 'never'. This ensures requests to '/base' are correctly matched when the base path is set to '/base', without requiring a trailing slash.

  • #13603 d038030 Thanks @sarah11918! - Adds the minimal starter template to the list of create astro options

    Good news if you're taking the introductory tutorial in docs, making a minimal reproduction, or just want to start a project with as little to rip out as possible. Astro's minimal (empty) template is now back as one of the options when running create astro@latest and starting a new project!

5.6.2

Patch Changes

  • #13606 793ecd9 Thanks @natemoo-re! - Fixes a regression that allowed prerendered code to leak into the server bundle.

  • #13576 1c60ec3 Thanks @ascorbic! - Reduces duplicate code in server islands scripts by extracting shared logic into a helper function.

  • #13588 57e59be Thanks @natemoo-re! - Fixes a memory leak when using SVG assets.

  • #13589 5a0563d Thanks @ematipico! - Deprecates the asset utility function emitESMImage() and adds a new emitImageMetadata() to be used instead

    The function emitESMImage() is now deprecated. It will continue to function, but it is no longer recommended nor supported. This function will be completely removed in a next major release of Astro.

    Please replace it with the new functionemitImageMetadata() as soon as you are able to do so:

    - import { emitESMImage } from "astro/assets/utils";
    + import { emitImageMetadata } from "astro/assets/utils";
    

    The new function returns the same signature as the previous one. However, the new function removes two deprecated arguments that were not meant to be exposed for public use: _watchMode and experimentalSvgEnabled. Since it was possible to access these with the old function, you may need to verify that your code still works as intended with emitImageMetadata().

  • #13596 3752519 Thanks @jsparkdev! - update vite to latest version to fix CVE

  • #13547 360cb91 Thanks @jsparkdev! - Updates vite to the latest version

  • #13548 e588527 Thanks @ryuapp! - Support for Deno to install npm pacakges.

    Deno requires npm prefix to install packages on npm. For example, to install react, we need to run deno add npm:react. But currently the command executed is deno add react, which doesn't work. So, we change the package names to have an npm prefix if you are using Deno.

  • #13587 a0774b3 Thanks @robertoms99! - Fixes an issue with the client router where some attributes of the root element were not updated during swap, including the transition scope.

5.6.1

Patch Changes

5.6.0

Minor Changes

  • #13403 dcb9526 Thanks @yurynix! - Adds a new optional prerenderedErrorPageFetch option in the Adapter API to allow adapters to provide custom implementations for fetching prerendered error pages.

    Now, adapters can override the default fetch() behavior, for example when fetch() is unavailable or when you cannot call the server from itself.

    The following example provides a custom fetch for 500.html and 404.html, reading them from disk instead of performing an HTTP call:

    return app.render(request, {
      prerenderedErrorPageFetch: async (url: string): Promise<Response> => {
        if (url.includes("/500")) {
            const content = await fs.promises.readFile("500.html", "utf-8");
            return new Response(content, {
              status: 500,
              headers: { "Content-Type": "text/html" },
            });
        }
        const content = await fs.promises.readFile("404.html", "utf-8");
          return new Response(content, {
            status: 404,
            headers: { "Content-Type": "text/html" },
          });
    });
    

    If no value is provided, Astro will fallback to its default behavior for fetching error pages.

    Read more about this feature in the Adapter API reference.

  • #13482 ff257df Thanks @florian-lefebvre! - Updates Astro config validation to also run for the Integration API. An error log will specify which integration is failing the validation.

    Now, Astro will first validate the user configuration, then validate the updated configuration after each integration astro:config:setup hook has run. This means updateConfig() calls will no longer accept invalid configuration.

    This fixes a situation where integrations could potentially update a project with a malformed configuration. These issues should now be caught and logged so that you can update your integration to only set valid configurations.

  • #13405 21e7e80 Thanks @Marocco2! - Adds a new eagerness option for prefetch() when using experimental.clientPrerender

    With the experimental clientPrerender flag enabled, you can use the eagerness option on prefetch() to suggest to the browser how eagerly it should prefetch/prerender link targets.

    This follows the same API described in the Speculation Rules API and allows you to balance the benefit of reduced wait times against bandwidth, memory, and CPU costs for your site visitors.

    For example, you can now use prefetch() programmatically with large sets of links and avoid browser limits in place to guard against over-speculating (prerendering/prefetching too many links). Set eagerness: 'moderate' to take advantage of First In, First Out (FIFO) strategies and browser heuristics to let the browser decide when to prerender/prefetch them and in what order:

    <a class="link-moderate" href="/nice-link-1">A Nice Link 1</a>
    <a class="link-moderate" href="/nice-link-2">A Nice Link 2</a>
    <a class="link-moderate" href="/nice-link-3">A Nice Link 3</a>
    <a class="link-moderate" href="/nice-link-4">A Nice Link 4</a>
    ...
    <a class="link-moderate" href="/nice-link-20">A Nice Link 20</a>
    <script>
      import { prefetch } from 'astro:prefetch';
      const linkModerate = document.getElementsByClassName('link-moderate');
      linkModerate.forEach((link) => prefetch(link.getAttribute('href'), { eagerness: 'moderate' }));
    </script>
    
  • #13482 ff257df Thanks @florian-lefebvre! - Improves integrations error handling

    If an error is thrown from an integration hook, an error log will now provide information about the concerned integration and hook

Patch Changes

  • #13539 c43bf8c Thanks @ascorbic! - Adds a new session.load() method to the experimental session API that allows you to load a session by ID.

    When using the experimental sessions API, you don't normally need to worry about managing the session ID and cookies: Astro automatically reads the user's cookies and loads the correct session when needed. However, sometimes you need more control over which session to load.

    The new load() method allows you to manually load a session by ID. This is useful if you are handling the session ID yourself, or if you want to keep track of a session without using cookies. For example, you might want to restore a session from a logged-in user on another device, or work with an API endpoint that doesn't use cookies.

    // src/pages/api/cart.ts
    import type { APIRoute } from 'astro';
    
    export const GET: APIRoute = async ({ session, request }) => {
      // Load the session from a header instead of cookies
      const sessionId = request.headers.get('x-session-id');
      await session.load(sessionId);
      const cart = await session.get('cart');
      return Response.json({ cart });
    };
    

    If a session with that ID doesn't exist, a new one will be created. This allows you to generate a session ID in the client if needed.

    For more information, see the experimental sessions docs.

  • #13488 d777420 Thanks @stramel! - BREAKING CHANGE to the experimental SVG Component API only

    Removes some previously available prop, attribute, and configuration options from the experimental SVG API. These items are no longer available and must be removed from your code:

    • The title prop has been removed until we can settle on the correct balance between developer experience and accessibility. Please replace any title props on your components with aria-label:

      - <Logo title="My Company Logo" />
      + <Logo aria-label="My Company Logo" />
      
    • Sprite mode has been temporarily removed while we consider a new implementation that addresses how this feature was being used in practice. This means that there are no longer multiple mode options, and all SVGs will be inline. All instances of mode must be removed from your project as you can no longer control a mode:

      - <Logo mode="inline" />
      + <Logo />
      
      import { defineConfig } from 'astro'
      
      export default defineConfig({
        experimental: {
      -    svg: {
      -      mode: 'sprite'
      -    },
      +   svg: true
        }
      });
      
    • The default role is no longer applied due to developer feedback. Please add the appropriate role on each component individually as needed:

      - <Logo />
      + <Logo role="img" /> // To keep the role that was previously applied by default
      
    • The size prop has been removed to better work in combination with viewBox and additional styles/attributes. Please replace size with explicit width and height attributes:

      - <Logo size={64} />
      + <Logo width={64} height={64} />
      

5.5.6

Patch Changes

  • #13429 06de673 Thanks @ematipico! - The ActionAPIContext.rewrite method is deprecated and will be removed in a future major version of Astro

  • #13524 82cd583 Thanks @ematipico! - Fixes a bug where the functions Astro.preferredLocale and Astro.preferredLocaleList would return the incorrect locales when the Astro configuration specifies a list of codes. Before, the functions would return the path, instead now the functions return a list built from codes.

  • #13526 ff9d69e Thanks @jsparkdev! - update vite to the latest version

5.5.5

Patch Changes

  • #13510 5b14d33 Thanks @florian-lefebvre! - Fixes a case where astro:env secrets used in actions would not be available

  • #13485 018fbe9 Thanks @ascorbic! - Fixes a bug that caused cookies to ignore custom decode function if has() had been called before

  • #13505 a98ae5b Thanks @ematipico! - Updates the dependency vite to the latest.

  • #13483 fc2dcb8 Thanks @ematipico! - Fixes a bug where an Astro adapter couldn't call the middleware when there isn't a route that matches the incoming request.

5.5.4

Patch Changes

5.5.3

Patch Changes

  • #13437 013fa87 Thanks @Vardhaman619! - Handle server.allowedHosts when the value is true without attempting to push it into an array.

  • #13324 ea74336 Thanks @ematipico! - Upgrade to shiki v3

  • #13372 7783dbf Thanks @ascorbic! - Fixes a bug that caused some very large data stores to save incomplete data.

  • #13358 8c21663 Thanks @ematipico! - Adds a new function called insertPageRoute to the Astro Container API.

    The new function is useful when testing routes that, for some business logic, use Astro.rewrite.

    For example, if you have a route /blog/post and for some business decision there's a rewrite to /generic-error, the container API implementation will look like this:

    import Post from '../src/pages/Post.astro';
    import GenericError from '../src/pages/GenericError.astro';
    import { experimental_AstroContainer as AstroContainer } from 'astro/container';
    
    const container = await AstroContainer.create();
    container.insertPageRoute('/generic-error', GenericError);
    const result = await container.renderToString(Post);
    console.log(result); // this should print the response from GenericError.astro
    

    This new method only works for page routes, which means that endpoints aren't supported.

  • #13426 565583b Thanks @ascorbic! - Fixes a bug that caused the astro add command to ignore the --yes flag for third-party integrations

  • #13428 9cac9f3 Thanks @matthewp! - Prevent bad value in x-forwarded-host from crashing request

  • #13432 defad33 Thanks @P4tt4te! - Fix an issue in the Container API, where the renderToString function doesn't render adequately nested slots when they are components.

  • Updated dependencies [ea74336]:

    • @astrojs/markdown-remark@6.3.1

5.5.2

Patch Changes

  • #13415 be866a1 Thanks @ascorbic! - Reuses experimental session storage object between requests. This prevents memory leaks and improves performance for drivers that open persistent connections to a database.

  • #13420 2f039b9 Thanks @ematipico! - It fixes an issue that caused some regressions in how styles are bundled.

5.5.1

Patch Changes

5.5.0

Minor Changes

  • #13402 3e7b498 Thanks @ematipico! - Adds a new experimental flag called experimental.preserveScriptOrder that renders <script> and <style> tags in the same order as they are defined.

    When rendering multiple <style> and <script> tags on the same page, Astro currently reverses their order in your generated HTML output. This can give unexpected results, for example CSS styles being overridden by earlier defined style tags when your site is built.

    With the new preserveScriptOrder flag enabled, Astro will generate the styles in the order they are defined:

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

    For example, the following component has two <style> tags, and both define the same style for the body tag:

    <p>I am a component</p>
    <style>
      body {
        background: red;
      }
    </style>
    <style>
      body {
        background: yellow;
      }
    </style>
    

    Once the project is compiled, Astro will create an inline style where yellow appears first, and then red. Ultimately, the red background is applied:

    body {
      background: #ff0;
    }
    body {
      background: red;
    }
    

    When experimental.preserveScriptOrder is set to true, the order of the two styles is kept as it is, and in the style generated red appears first, and then yellow:

    body {
      background: red;
    }
    body {
      background: #ff0;
    }
    

    This is a breaking change to how Astro renders project code that contains multiple <style> and <script> tags in the same component. If you were previously compensating for Astro's behavior by writing these out of order, you will need to update your code.

    This will eventually become the new default Astro behavior, so we encourage you to add this experimental style and script ordering as soon as you are able! This will help us test the new behavior and ensure your code is ready when this becomes the new normal.

    For more information as this feature develops, please see the experimental script order docs.

  • #13352 cb886dc Thanks @delucis! - Adds support for a new experimental.headingIdCompat flag

    By default, Astro removes a trailing - from the end of IDs it generates for headings ending with special characters. This differs from the behavior of common Markdown processors.

    You can now disable this behavior with a new configuration flag:

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

    This can be useful when heading IDs and anchor links need to behave consistently across your site and other platforms such as GitHub and npm.

    If you are using the rehypeHeadingIds plugin directly, you can also pass this new option:

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    import { rehypeHeadingIds } from '@astrojs/markdown-remark';
    import { otherPluginThatReliesOnHeadingIDs } from 'some/plugin/source';
    
    export default defineConfig({
      markdown: {
        rehypePlugins: [
          [rehypeHeadingIds, { experimentalHeadingIdCompat: true }],
          otherPluginThatReliesOnHeadingIDs,
        ],
      },
    });
    
  • #13311 a3327ff Thanks @chrisirhc! - Adds a new configuration option for Markdown syntax highlighting excludeLangs

    This option provides better support for diagramming tools that rely on Markdown code blocks, such as Mermaid.js and D2 by allowing you to exclude specific languages from Astro's default syntax highlighting.

    This option allows you to avoid rendering conflicts with tools that depend on the code not being highlighted without forcing you to disable syntax highlighting for other code blocks.

    The following example configuration will exclude highlighting for mermaid and math code blocks:

    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      markdown: {
        syntaxHighlight: {
          type: 'shiki',
          excludeLangs: ['mermaid', 'math'],
        },
      },
    });
    

    Read more about this new option in the Markdown syntax highlighting configuration docs.

Patch Changes

  • #13404 4e78b4d Thanks @ascorbic! - Fixes a bug in error handling that saving a content file with a schema error would display an "unhandled rejection" error instead of the correct schema error

  • #13379 d59eb22 Thanks @martrapp! - Fixes an edge case where the client router executed scripts twice when used with a custom swap function that only swaps parts of the DOM.

  • #13393 6b8fdb8 Thanks @renovate! - Updates primsjs to version 1.30.0, which adds support for more languages and fixes a security advisory which does not affect Astro.

  • #13374 7b75bc5 Thanks @ArmandPhilippot! - Fixes the documentation of the i18n configuration where manual was presented as a key of routing instead of an available value.

  • #13380 9bfa6e6 Thanks @martrapp! - Fixes an issue where astro:page-load fires before all scripts are executed

  • #13407 0efdc22 Thanks @ascorbic! - Displays correct error message when sharp isn't installed

  • Updated dependencies [cb886dc, a3327ff]:

    • @astrojs/markdown-remark@6.3.0

5.4.3

Patch Changes

  • #13381 249d52a Thanks @martrapp! - Adds the types property to the viewTransition object when the ClientRouter simulates parts of the View Transition API on browsers w/o native support.

  • #13367 3ce4ad9 Thanks @ematipico! - Adds documentation to various utility functions used for remote image services

  • #13347 d83f92a Thanks @bluwy! - Updates internal CSS chunking behavior for Astro components' scoped styles. This may result in slightly more CSS chunks created, but should allow the scoped styles to only be included on pages that use them.

  • #13388 afadc70 Thanks @ematipico! - Fixes a bug where astro:config/server and astro:config/client had incorrect types.

  • #13355 042d1de Thanks @ematipico! - Adds documentation to the assets utilities for remote service images.

  • #13395 6d1c63f Thanks @bluwy! - Uses package-manager-detector to detect the package manager used in the project

  • #13363 a793636 Thanks @ematipico! - Fixes an issue where the internal function makeSvgComponent was incorrectly exposed as a public API.

  • Updated dependencies [042d1de]:

    • @astrojs/internal-helpers@0.6.1
    • @astrojs/markdown-remark@6.2.1

5.4.2

Patch Changes

5.4.1

Patch Changes

  • #13336 8f632ef Thanks @ematipico! - Fixes a regression where some asset utilities were move across monorepo, and not re-exported anymore.

  • #13320 b5dabe9 Thanks @{! - Adds support for typing experimental session data

    You can add optional types to your session data by creating a src/env.d.ts file in your project that extends the global App.SessionData interface. For example:

    declare namespace App {
      interface SessionData {
    
          id: string;
          email: string;
        };
        lastLogin: Date;
      }
    }
    

    Any keys not defined in this interface will be treated as any.

    Then when you access Astro.session in your components, any defined keys will be typed correctly:

    ---
    const user = await Astro.session.get('user');
    //    ^? const: user: { id: string; email: string; } | undefined
    
    const something = await Astro.session.get('something');
    //    ^? const: something: any
    
    Astro.session.set('user', 1);
    //    ^? Argument of type 'number' is not assignable to parameter of type '{ id: string; email: string; }'.
    ---
    

    See the experimental session docs for more information.

  • #13330 5e7646e Thanks @ematipico! - Fixes an issue with the conditional rendering of scripts.

    This change updates a v5.0 breaking change when experimental.directRenderScript became the default script handling behavior.

    If you have already successfully upgraded to Astro v5, you may need to review your script tags again and make sure they still behave as desired after this release. See the v5 Upgrade Guide for more details.

5.4.0

Minor Changes

  • #12052 5be12b2 Thanks @Fryuni! - Exposes extra APIs for scripting and testing.

    Config helpers

    Two new helper functions exported from astro/config:

    • mergeConfig() allows users to merge partially defined Astro configurations on top of a base config while following the merge rules of updateConfig() available for integrations.
    • validateConfig() allows users to validate that a given value is a valid Astro configuration and fills in default values as necessary.

    These helpers are particularly useful for integration authors and for developers writing scripts that need to manipulate Astro configurations programmatically.

    Programmatic build

    The build API now receives a second optional BuildOptions argument where users can specify:

    • devOutput (default false): output a development-based build similar to code transformed in astro dev.
    • teardownCompiler (default true): teardown the compiler WASM instance after build.

    These options provide more control when running Astro builds programmatically, especially for testing scenarios or custom build pipelines.

  • #13278 4a43c4b Thanks @ematipico! - Adds a new configuration option server.allowedHosts and CLI option --allowed-hosts.

    Now you can specify the hostnames that the dev and preview servers are allowed to respond to. This is useful for allowing additional subdomains, or running the dev server in a web container.

    allowedHosts checks the Host header on HTTP requests from browsers and if it doesn't match, it will reject the request to prevent CSRF and XSS attacks.

    astro dev --allowed-hosts=foo.bar.example.com,bar.example.com
    
    astro preview --allowed-hosts=foo.bar.example.com,bar.example.com
    
    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      server: {
        allowedHosts: ['foo.bar.example.com', 'bar.example.com'],
      },
    });
    

    This feature is the same as Vite's server.allowHosts configuration.

  • #13254 1e11f5e Thanks @p0lyw0lf! - Adds the ability to process and optimize remote images in Markdown files

    Previously, Astro only allowed local images to be optimized when included using ![]() syntax in plain Markdown files. Astro's image service could only display remote images without any processing.

    Now, Astro's image service can also optimize remote images written in standard Markdown syntax. This allows you to enjoy the benefits of Astro's image processing when your images are stored externally, for example in a CMS or digital asset manager.

    No additional configuration is required to use this feature! Any existing remote images written in Markdown will now automatically be optimized. To opt-out of this processing, write your images in Markdown using the HTML <img> tag instead. Note that images located in your public/ folder are still never processed.

Patch Changes

  • #13256 509fa67 Thanks @p0lyw0lf! - Adds experimental responsive image support in Markdown

    Previously, the experimental.responsiveImages feature could only provide responsive images when using the <Image /> and <Picture /> components.

    Now, images written with the ![]() Markdown syntax in Markdown and MDX files will generate responsive images by default when using this experimental feature.

    To try this experimental feature, set experimental.responsiveImages to true in your astro.config.mjs file:

    {
       experimental: {
          responsiveImages: true,
       },
    }
    

    Learn more about using this feature in the experimental responsive images feature reference.

    For a complete overview, and to give feedback on this experimental API, see the Responsive Images RFC.

  • #13323 80926fa Thanks @ematipico! - Updates esbuild and vite to the latest to avoid false positives audits warnings caused by esbuild.

  • #13313 9e7c71d Thanks @martrapp! - Fixes an issue where a form field named "attributes" shadows the form.attributes property.

  • #12052 5be12b2 Thanks @Fryuni! - Fixes incorrect config update when calling updateConfig from astro:build:setup hook.

    The function previously called a custom update config function made for merging an Astro config. Now it calls the appropriate mergeConfig() utility exported by Vite that updates functional options correctly.

  • #13303 5f72a58 Thanks @ematipico! - Fixes an issue where the dev server was applying second decoding of the URL of the incoming request, causing issues for certain URLs.

  • Updated dependencies [1e11f5e, 1e11f5e]:

    • @astrojs/internal-helpers@0.6.0
    • @astrojs/markdown-remark@6.2.0

5.3.1

Patch Changes

  • #13233 32fafeb Thanks @joshmkennedy! - Ensures consistent behaviour of Astro.rewrite/ctx.rewrite when using base and trailingSlash options.

  • #13003 ea79054 Thanks @chaegumi! - Fixes a bug that caused the vite.base value to be ignored when running astro dev

  • #13299 2e1321e Thanks @bluwy! - Uses tinyglobby for globbing files

  • #13233 32fafeb Thanks @joshmkennedy! - Ensures that Astro.url/ctx.url is correctly updated with the base path after rewrites.

    This change fixes an issue where Astro.url/ctx.url did not include the configured base path after Astro.rewrite was called. Now, the base path is correctly reflected in Astro.url.

    Previously, any rewrites performed through Astro.rewrite/ctx.rewrite failed to append the base path to Astro.url/ctx.rewrite, which could lead to incorrect URL handling in downstream logic. By fixing this, we ensure that all routes remain consistent and predictable after a rewrite.

    If you were relying on the work around of including the base path in astro.rewrite you can now remove it from the path.

5.3.0

Minor Changes

  • #13210 344e9bc Thanks @VitaliyR! - Handle HEAD requests to an endpoint when a handler is not defined.

    If an endpoint defines a handler for GET, but does not define a handler for HEAD, Astro will call the GET handler and return the headers and status but an empty body.

  • #13195 3b66955 Thanks @MatthewLymer! - Improves SSR performance for synchronous components by avoiding the use of Promises. With this change, SSR rendering of on-demand pages can be up to 4x faster.

  • #13145 8d4e566 Thanks @ascorbic! - Adds support for adapters auto-configuring experimental session storage drivers.

    Adapters can now configure a default session storage driver when the experimental.session flag is enabled. If a hosting platform has a storage primitive that can be used for session storage, the adapter can automatically configure the session storage using that driver. This allows Astro to provide a more seamless experience for users who want to use sessions without needing to manually configure the session storage.

Patch Changes

  • #13145 8d4e566 Thanks @ascorbic! - ⚠️ BREAKING CHANGE FOR EXPERIMENTAL SESSIONS ONLY ⚠️

    Changes the experimental.session option to a boolean flag and moves session config to a top-level value. This change is to allow the new automatic session driver support. You now need to separately enable the experimental.session flag, and then configure the session driver using the top-level session key if providing manual configuration.

    defineConfig({
      // ...
      experimental: {
    -    session: {
    -      driver: 'upstash',
    -    },
    +    session: true,
      },
    +  session: {
    +    driver: 'upstash',
    +  },
    });
    

    You no longer need to configure a session driver if you are using an adapter that supports automatic session driver configuration and wish to use its default settings.

    defineConfig({
      adapter: node({
        mode: "standalone",
      }),
      experimental: {
    -    session: {
    -      driver: 'fs',
    -      cookie: 'astro-cookie',
    -    },
    +    session: true,
      },
    +  session: {
    +    cookie: 'astro-cookie',
    +  },
    });
    

    However, you can still manually configure additional driver options or choose a non-default driver to use with your adapter with the new top-level session config option. For more information, see the experimental session docs.

  • #13101 2ed67d5 Thanks @corneliusroemer! - Fixes a bug where HEAD and OPTIONS requests for non-prerendered pages were incorrectly rejected with 403 FORBIDDEN

5.2.6

Patch Changes

5.2.5

Patch Changes

  • #13133 e76aa83 Thanks @ematipico! - Fixes a bug where Astro was failing to build an external redirect when the middleware was triggered

  • #13119 ac43580 Thanks @Hacksore! - Adds extra guidance in the terminal when using the astro add tailwind CLI command

    Now, users are given a friendly reminder to import the stylesheet containing their Tailwind classes into any pages where they want to use Tailwind. Commonly, this is a shared layout component so that Tailwind styling can be used on multiple pages.

5.2.4

Patch Changes

  • #13130 b71bd10 Thanks @ascorbic! - Fixes a bug that caused duplicate slashes inside query params to be collapsed

  • #13131 d60c742 Thanks @ascorbic! - Ignores trailing slashes for endpoints with file extensions in the route

  • Updated dependencies [b71bd10]:

    • @astrojs/internal-helpers@0.5.1

5.2.3

Patch Changes

  • #13113 3a26e45 Thanks @unprintable123! - Fixes the bug that rewrite will pass encoded url to the dynamic routing and cause params mismatch.

  • #13111 23978dd Thanks @ascorbic! - Fixes a bug that caused injected endpoint routes to return not found when trailingSlash was set to always

  • #13112 0fa5c82 Thanks @ematipico! - Fixes a bug where the i18n middleware was blocking a server island request when the prefixDefaultLocale option is set to true

5.2.2

Patch Changes

  • #13106 187c4d3 Thanks @ascorbic! - Fixes a bug that caused peer dependency errors when running astro add tailwind

5.2.1

Patch Changes

  • #13095 740eb60 Thanks @ascorbic! - Fixes a bug that caused some dev server asset requests to return 404 when trailingSlash was set to "always"

5.2.0

Minor Changes

  • #12994 5361755 Thanks @ascorbic! - Redirects trailing slashes for on-demand pages

    When the trailingSlash option is set to always or never, on-demand rendered pages will now redirect to the correct URL when the trailing slash doesn't match the configuration option. This was previously the case for static pages, but now works for on-demand pages as well.

    Now, it doesn't matter whether your visitor navigates to /about/, /about, or even /about///. In production, they'll always end up on the correct page. For GET requests, the redirect will be a 301 (permanent) redirect, and for all other request methods, it will be a 308 (permanent, and preserve the request method) redirect.

    In development, you'll see a helpful 404 page to alert you of a trailing slash mismatch so you can troubleshoot routes.

  • #12979 e621712 Thanks @ematipico! - Adds support for redirecting to external sites with the redirects configuration option.

    Now, you can redirect routes either internally to another path or externally by providing a URL beginning with http or https:

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      redirects: {
        '/blog': 'https://example.com/blog',
        '/news': {
          status: 302,
          destination: 'https://example.com/news',
        },
      },
    });
    
  • #13084 0f3be31 Thanks @ematipico! - Adds a new experimental virtual module astro:config that exposes a type-safe subset of your astro.config.mjs configuration

    The virtual module exposes two sub-paths for controlled access to your configuration:

    • astro:config/client: exposes config information that is safe to expose to the client.
    • astro:config/server: exposes additional information that is safe to expose to the server, such as file/dir paths.

    To enable this new virtual module, add the experimental.serializeManifest feature flag to your Astro config:

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

    Then, you can access the module in any file inside your project to import and use values from your Astro config:

    // src/utils.js
    import { trailingSlash } from 'astro:config/client';
    
    function addForwardSlash(path) {
      if (trailingSlash === 'always') {
        return path.endsWith('/') ? path : path + '/';
      } else {
        return path;
      }
    }
    

    For a complete overview, and to give feedback on this experimental API, see the Serialized Manifest RFC.

Patch Changes

  • #13049 2ed4bd9 Thanks @florian-lefebvre! - Updates astro add tailwind to add the @tailwindcss/vite plugin instead of the @astrojs/tailwind integration

  • #12994 5361755 Thanks @ascorbic! - Returns a more helpful 404 page in dev if there is a trailing slash mismatch between the route requested and the trailingSlash configuration

  • #12666 037495d Thanks @Thodor12! - Added additional generated typings for the content layer

  • Updated dependencies [5361755, db252e0]:

    • @astrojs/internal-helpers@0.5.0
    • @astrojs/markdown-remark@6.1.0

5.1.10

Patch Changes

  • #13058 1a14b53 Thanks @ascorbic! - Fixes broken type declaration

  • #13059 e36837f Thanks @ascorbic! - Fixes a bug that caused tsconfig path aliases to break if there was more than one wildcard pattern

  • #13045 c7f1366 Thanks @mtwilliams-code! - Fixes a bug where the some utility functions of the astro:i18n virtual module would return an incorrect result when trailingSlash is set to never

5.1.9

Patch Changes

  • #12986 8911bda Thanks @wetheredge! - Updates types and dev toolbar for ARIA 1.2 attributes and roles

  • #12892 8f520f1 Thanks @louisescher! - Adds a more descriptive error when a content collection entry has an invalid ID.

  • #13031 f576519 Thanks @florian-lefebvre! - Updates the server islands encoding logic to only escape the script end tag open delimiter and opening HTML comment syntax

  • #13026 1d272f6 Thanks @ascorbic! - Fixes a regression that prevented the import of Markdown files as raw text or URLs.

5.1.8

Patch Changes

  • #12998 9ce0038 Thanks @Kynson! - Fixes the issue that audit incorrectly flag images as above the fold when the scrolling container is not body

  • #12990 2e12f1d Thanks @ascorbic! - Fixes a bug that caused references to be incorrectly reported as invalid

  • #12984 2d259cf Thanks @ascorbic! - Fixes a bug in dev where files would stop being watched if the Astro config file was edited

  • #12984 2d259cf Thanks @ascorbic! - Fixes a bug where the content layer would use an outdated version of the Astro config if it was edited in dev

  • #12982 429aa75 Thanks @bluwy! - Fixes an issue where server islands do not work in projects that use an adapter but only have prerendered pages. If an adapter is added, the server island endpoint will now be added by default.

  • #12995 78fd73a Thanks @florian-lefebvre! - Fixes a case where astro:actions types would not work when using src/actions.ts

  • #13011 cf30880 Thanks @ascorbic! - Upgrades Vite

  • #12733 bbf1d88 Thanks @ascorbic! - Fixes a bug that caused the dev server to return an error if requesting "//"

  • #13001 627aec3 Thanks @ascorbic! - Fixes a bug that caused Astro to attempt to inject environment variables into non-source files, causing performance problems and broken builds

5.1.7

Patch Changes

  • #12361 3d89e62 Thanks @LunaticMuch! - Upgrades the esbuild version to match vite

  • #12980 1a026af Thanks @florian-lefebvre! - Fixes a case where setting the status of a page to 404 in development would show the default 404 page (or custom one if provided) instead of using the current page

  • #12182 c30070b Thanks @braden-w! - Improves matching of 404 and 500 routes

  • Updated dependencies [3d89e62]:

    • @astrojs/markdown-remark@6.0.2

5.1.6

Patch Changes

5.1.5

Patch Changes

  • #12934 673a518 Thanks @ematipico! - Fixes a regression where the Astro Container didn't work during the build, using pnpm

  • #12955 db447f2 Thanks @martrapp! - Lets TypeScript know about the "blocking" and "disabled" attributes of the <link> element.

  • #12922 faf74af Thanks @adamchal! - Improves performance of static asset generation by fixing a bug that caused image transforms to be performed serially. This fix ensures that processing uses all CPUs when running in a multi-core environment.

  • #12947 3c2292f Thanks @ascorbic! - Fixes a bug that caused empty content collections when running dev with NODE_ENV set

5.1.4

Patch Changes

  • #12927 ad2a752 Thanks @ematipico! - Fixes a bug where Astro attempted to decode a request URL multiple times, resulting in an unexpected behaviour when decoding the character %

  • #12912 0c0c66b Thanks @florian-lefebvre! - Improves the config error for invalid combinations of context and access properties under env.schema

  • #12935 3d47e6b Thanks @AirBorne04! - Fixes an issue where Astro.locals coming from an adapter weren't available in the 404.astro, when using the astro dev command,

  • #12925 44841fc Thanks @ascorbic! - Ensures image styles are not imported unless experimental responsive images are enabled

  • #12926 8e64bb7 Thanks @oliverlynch! - Improves remote image cache efficiency by separating image data and metadata into a binary and sidecar JSON file.

  • #12920 8b9d530 Thanks @bluwy! - Processes markdown with empty body as remark and rehype plugins may add additional content or frontmatter

  • #12918 fd12a26 Thanks @lameuler! - Fixes a bug where the logged output path does not match the actual output path when using build.format: 'preserve'

  • #12676 2ffc0fc Thanks @koyopro! - Allows configuring Astro modules TypeScript compilation with the vite.esbuild config

  • #12938 dbb04f3 Thanks @ascorbic! - Fixes a bug where content collections would sometimes appear empty when first running astro dev

  • #12937 30edb6d Thanks @ematipico! - Fixes a bug where users could use Astro.request.headers during a rewrite inside prerendered routes. This an invalid behaviour, and now Astro will show a warning if this happens.

  • #12937 30edb6d Thanks @ematipico! - Fixes an issue where the use of Astro.rewrite would trigger the invalid use of Astro.request.headers

5.1.3

Patch Changes

  • #12877 73a0788 Thanks @bluwy! - Fixes sourcemap warning generated by the astro:server-islands Vite plugin

  • #12906 2d89492 Thanks @ascorbic! - Fixes a bug that caused pages that return an empty array from getStaticPath to match every path

  • 011fa0f Thanks @florian-lefebvre! - Fixes a case where astro:content types would be erased when restarting the dev server

  • #12907 dbf1275 Thanks @florian-lefebvre! - Fixes a regression around the server islands route, which was not passed to the adapters astro:build:done hook

  • #12818 579bd93 Thanks @ascorbic! - Fixes race condition where dev server would attempt to load collections before the content had loaded

  • #12883 fbac92f Thanks @kaytwo! - Fixes a bug where responses can be returned before session data is saved

  • #12815 3acc654 Thanks @ericswpark! - Some non-index files that were incorrectly being treated as index files are now excluded

  • #12884 d7e97a7 Thanks @ascorbic! - Adds render() to stub content types

  • #12883 fbac92f Thanks @kaytwo! - Fixes a bug where session data could be corrupted if it is changed after calling .set()

  • #12827 7b5dc6f Thanks @sinskiy! - Fixes an issue when crawlers try to index Server Islands thinking that Server Islands are pages

5.1.2

Patch Changes

  • #12798 7b0cb85 Thanks @ascorbic! - Improves warning logs for invalid content collection configuration

  • #12781 96c4b92 Thanks @ascorbic! - Fixes a regression that caused default() to not work with reference()

  • #12820 892dd9f Thanks @ascorbic! - Fixes a bug that caused cookies to not be deleted when destroying a session

  • #12864 440d8a5 Thanks @kaytwo! - Fixes a bug where the session ID wasn't correctly regenerated

  • #12768 524c855 Thanks @ematipico! - Fixes an issue where Astro didn't print error logs when Astro Islands were used in incorrect cases.

  • #12814 f12f111 Thanks @ematipico! - Fixes an issue where Astro didn't log anything in case a file isn't created during the build.

  • #12875 e109002 Thanks @ascorbic! - Fixes a bug in emulated legacy collections where the entry passed to the getCollection filter function did not include the legacy entry fields.

  • #12768 524c855 Thanks @ematipico! - Fixes an issue where Astro was printing the incorrect output format when running the astro build command

  • #12810 70a9f0b Thanks @louisescher! - Fixes server islands failing to check content-type header under certain circumstances

    Sometimes a reverse proxy or similar service might modify the content-type header to include the charset or other parameters in the media type of the response. This previously wasn't handled by the client-side server island script and thus removed the script without actually placing the requested content in the DOM. This fix makes it so the script checks if the header starts with the proper content type instead of exactly matching text/html, so the following will still be considered a valid header: text/html; charset=utf-8

  • #12816 7fb2184 Thanks @ematipico! - Fixes an issue where an injected route entrypoint wasn't correctly marked because the resolved file path contained a query parameter.

    This fixes some edge case where some injected entrypoint were not resolved when using an adapter.

5.1.1

Patch Changes

5.1.0

Minor Changes

  • #12441 b4fec3c Thanks @ascorbic! - Adds experimental session support

    Sessions are used to store user state between requests for server-rendered pages, such as login status, shopping cart contents, or other user-specific data.

    ---
    export const prerender = false; // Not needed in 'server' mode
    const cart = await Astro.session.get('cart');
    ---
    
    <a href="/checkout">🛒 {cart?.length ?? 0} items</a>
    

    Sessions are available in on-demand rendered/SSR pages, API endpoints, actions and middleware. To enable session support, you must configure a storage driver.

    If you are using the Node.js adapter, you can use the fs driver to store session data on the filesystem:

    // astro.config.mjs
    {
      adapter: node({ mode: 'standalone' }),
      experimental: {
        session: {
          // Required: the name of the unstorage driver
          driver: "fs",
        },
      },
    }
    

    If you are deploying to a serverless environment, you can use drivers such as redis, netlify-blobs, vercel-kv, or cloudflare-kv-binding and optionally pass additional configuration options.

    For more information, including using the session API with other adapters and a full list of supported drivers, see the docs for experimental session support. For even more details, and to leave feedback and participate in the development of this feature, the Sessions RFC.

  • #12426 3dc02c5 Thanks @oliverlynch! - Improves asset caching of remote images

    Astro will now store entity tags and the Last-Modified date for cached remote images and use them to revalidate the cache when it goes stale.

  • #12721 c9d5110 Thanks @florian-lefebvre! - Adds a new getActionPath() helper available from astro:actions

    Astro 5.1 introduces a new helper function, getActionPath() to give you more flexibility when calling your action.

    Calling getActionPath() with your action returns its URL path so you can make a fetch() request with custom headers, or use your action with an API such as navigator.sendBeacon(). Then, you can handle the custom-formatted returned data as needed, just as if you had called an action directly.

    This example shows how to call a defined like action passing the Authorization header and the keepalive option:

    <script>
      // src/components/my-component.astro
      import { actions, getActionPath } from 'astro:actions';
    
      await fetch(getActionPath(actions.like), {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Authorization: 'Bearer YOUR_TOKEN',
        },
        body: JSON.stringify({ id: 'YOUR_ID' }),
        keepalive: true,
      });
    </script>
    

    This example shows how to call the same like action using the sendBeacon API:

    <script>
      // src/components/my-component.astro
      import { actions, getActionPath } from 'astro:actions';
    
      navigator.sendBeacon(
        getActionPath(actions.like),
        new Blob([JSON.stringify({ id: 'YOUR_ID' })], {
          type: 'application/json',
        }),
      );
    </script>
    

Patch Changes

  • #12786 e56af4a Thanks @ematipico! - Fixes an issue where Astro i18n didn't properly show the 404 page when using fallback and the option prefixDefaultLocale set to true.

  • #12758 483da89 Thanks @delucis! - Adds types for ?url&inline and ?url&no-inline import queries added in Vite 6

  • #12763 8da2318 Thanks @rbsummers! - Fixed changes to vite configuration made in the astro:build:setup integration hook having no effect when target is "client"

  • #12767 36c1e06 Thanks @ascorbic! - Clears the content layer cache when the Astro config is changed

5.0.9

Patch Changes

5.0.8

Patch Changes

5.0.7

Patch Changes

5.0.6

Patch Changes

5.0.5

Patch Changes

  • #12705 0d1eab5 Thanks @ascorbic! - Fixes a bug where MDX files with certain characters in the name would cause builds to fail

  • #12707 2aaed2d Thanks @ematipico! - Fixes a bug where the middleware was incorrectly imported during the build

  • #12697 1c4a032 Thanks @ascorbic! - Fix a bug that caused builds to fail if an image had a quote mark in its name

  • #12694 495f46b Thanks @ematipico! - Fixes a bug where the experimental feature experimental.svg was incorrectly used when generating ESM images

  • #12658 3169593 Thanks @jurajkapsz! - Fixes astro info copy to clipboard process not returning to prompt in certain cases.

  • #12712 b01c74a Thanks @ascorbic! - Fixes a bug which misidentified pages as markdown if a query string ended in a markdown extension

5.0.4

Patch Changes

5.0.3

Patch Changes

  • #12645 8704c54 Thanks @sarah11918! - Updates some reference links in error messages for new v5 docs.

  • #12641 48ca399 Thanks @ascorbic! - Fixes a bug where astro info --copy wasn't working correctly on macOS systems.

  • #12461 62939ad Thanks @kyr0! - Removes the misleading log message telling that a custom renderer is not recognized while it clearly is and works.

  • #12642 ff18b9c Thanks @ematipico! - Provides more information when logging a warning for accessing Astro.request.headers in prerendered pages

  • #12634 03958d9 Thanks @delucis! - Improves error message formatting for user config and content collection frontmatter

  • #12547 6b6e18d Thanks @mtwilliams-code! - Fixes a bug where URL search parameters weren't passed when using the i18n fallback feature.

  • #12449 e6b8017 Thanks @apatel369! - Fixes an issue where the custom assetFileNames configuration caused assets to be incorrectly moved to the server directory instead of the client directory, resulting in 404 errors when accessed from the client side.

  • #12518 e216250 Thanks @ematipico! - Fixes an issue where SSR error pages would return duplicated custom headers.

  • #12625 74bfad0 Thanks @ematipico! - Fixes an issue where the experimental.svg had incorrect type, resulting in some errors in the editors.

  • #12631 dec0305 Thanks @ascorbic! - Fixes a bug where the class attribute was rendered twice on the image component

  • #12623 0e4fecb Thanks @ascorbic! - Correctly handles images in content collections with uppercase file extensions

  • #12633 8a551c1 Thanks @bluwy! - Cleans up content layer sync during builds and programmatic sync() calls

  • #12640 22e405a Thanks @ascorbic! - Fixes a bug that caused content collections to be returned empty when run in a test environment

  • #12613 306c9f9 Thanks @matthewp! - Fix use of cloned requests in middleware with clientAddress

    When using context.clientAddress or Astro.clientAddress Astro looks up the address in a hidden property. Cloning a request can cause this hidden property to be lost.

    The fix is to pass the address as an internal property instead, decoupling it from the request.

5.0.2

Patch Changes

5.0.1

Patch Changes

5.0.0

Major Changes

  • #11798 e9e2139 Thanks @matthewp! - Unflag globalRoutePriority

    The previously experimental feature globalRoutePriority is now the default in Astro 5.

    This was a refactoring of route prioritization in Astro, making it so that injected routes, file-based routes, and redirects are all prioritized using the same logic. This feature has been enabled for all Starlight projects since it was added and should not affect most users.

  • #11864 ee38b3a Thanks @ematipico! - ### [changed]: entryPoint type inside the hook astro:build:ssr In Astro v4.x, the entryPoint type was RouteData.

    Astro v5.0 the entryPoint type is IntegrationRouteData, which contains a subset of the RouteData type. The fields isIndex and fallbackRoutes were removed.

    What should I do?

    Update your adapter to change the type of entryPoint from RouteData to IntegrationRouteData.

    -import type {RouteData} from 'astro';
    +import type {IntegrationRouteData} from "astro"
    
    -function useRoute(route: RouteData) {
    +function useRoute(route: IntegrationRouteData) {
    
    }
    
  • #12524 9f44019 Thanks @bluwy! - Bumps Vite to ^6.0.1 and handles its breaking changes

  • #10742 b6fbdaa Thanks @ematipico! - The lowest version of Node supported by Astro is now Node v18.17.1 and higher.

  • #11916 46ea29f Thanks @bluwy! - Updates how the build.client and build.server option values get resolved to match existing documentation. With this fix, the option values will now correctly resolve relative to the outDir option. So if outDir is set to ./dist/nested/, then by default:

    • build.client will resolve to <root>/dist/nested/client/
    • build.server will resolve to <root>/dist/nested/server/

    Previously the values were incorrectly resolved:

    • build.client was resolved to <root>/dist/nested/dist/client/
    • build.server was resolved to <root>/dist/nested/dist/server/

    If you were relying on the previous build paths, make sure that your project code is updated to the new build paths.

  • #11982 d84e444 Thanks @Princesseuh! - Adds a default exclude and include value to the tsconfig presets. {projectDir}/dist is now excluded by default, and {projectDir}/.astro/types.d.ts and {projectDir}/**/* are included by default.

    Both of these options can be overridden by setting your own values to the corresponding settings in your tsconfig.json file.

  • #11861 3ab3b4e Thanks @bluwy! - Cleans up Astro-specific metadata attached to vfile.data in Remark and Rehype plugins. Previously, the metadata was attached in different locations with inconsistent names. The metadata is now renamed as below:

    • vfile.data.__astroHeadings -> vfile.data.astro.headings
    • vfile.data.imagePaths -> vfile.data.astro.imagePaths

    The types of imagePaths has also been updated from Set<string> to string[]. The vfile.data.astro.frontmatter metadata is left unchanged.

    While we don't consider these APIs public, they can be accessed by Remark and Rehype plugins that want to re-use Astro's metadata. If you are using these APIs, make sure to access them in the new locations.

  • #11987 bf90a53 Thanks @florian-lefebvre! - The locals object can no longer be overridden

    Middleware, API endpoints, and pages can no longer override the locals object in its entirety. You can still append values onto the object, but you can not replace the entire object and delete its existing values.

    If you were previously overwriting like so:

    ctx.locals = {
      one: 1,
      two: 2,
    };
    

    This can be changed to an assignment on the existing object instead:

    Object.assign(ctx.locals, {
      one: 1,
      two: 2,
    });
    
  • #11908 518433e Thanks @Princesseuh! - The image.endpoint config now allow customizing the route of the image endpoint in addition to the entrypoint. This can be useful in niche situations where the default route /_image conflicts with an existing route or your local server setup.

    import { defineConfig } from 'astro/config';
    
    defineConfig({
      image: {
        endpoint: {
          route: '/image',
          entrypoint: './src/image_endpoint.ts',
        },
      },
    });
    
  • #12008 5608338 Thanks @Princesseuh! - Welcome to the Astro 5 beta! This release has no changes from the latest alpha of this package, but it does bring us one step closer to the final, stable release.

    Starting from this release, no breaking changes will be introduced unless absolutely necessary.

    To learn how to upgrade, check out the Astro v5.0 upgrade guide in our beta docs site.

  • #11679 ea71b90 Thanks @florian-lefebvre! - The astro:env feature introduced behind a flag in v4.10.0 is no longer experimental and is available for general use. If you have been waiting for stabilization before using astro:env, you can now do so.

    This feature lets you configure a type-safe schema for your environment variables, and indicate whether they should be available on the server or the client.

    To configure a schema, add the env option to your Astro config and define your client and server variables. If you were previously using this feature, please remove the experimental flag from your Astro config and move your entire env configuration unchanged to a top-level option.

    import { defineConfig, envField } from 'astro/config';
    
    export default defineConfig({
      env: {
        schema: {
          API_URL: envField.string({ context: 'client', access: 'public', optional: true }),
          PORT: envField.number({ context: 'server', access: 'public', default: 4321 }),
          API_SECRET: envField.string({ context: 'server', access: 'secret' }),
        },
      },
    });
    

    You can import and use your defined variables from the appropriate /client or /server module:

    ---
    import { API_URL } from 'astro:env/client';
    import { API_SECRET_TOKEN } from 'astro:env/server';
    
    const data = await fetch(`${API_URL}/users`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${API_SECRET_TOKEN}`,
      },
    });
    ---
    
    <script>
      import { API_URL } from 'astro:env/client';
    
      fetch(`${API_URL}/ping`);
    </script>
    

    Please see our guide to using environment variables for more about this feature.

  • #11806 f7f2338 Thanks @Princesseuh! - Removes the assets property on supportedAstroFeatures for adapters, as it did not reflect reality properly in many cases.

    Now, relating to assets, only a single sharpImageService property is available, determining if the adapter is compatible with the built-in sharp image service.

  • #11864 ee38b3a Thanks @ematipico! - ### [changed]: routes type inside the hook astro:build:done In Astro v4.x, the routes type was RouteData.

    Astro v5.0 the routes type is IntegrationRouteData, which contains a subset of the RouteData type. The fields isIndex and fallbackRoutes were removed.

    What should I do?

    Update your adapter to change the type of routes from RouteData to IntegrationRouteData.

    -import type {RouteData} from 'astro';
    +import type {IntegrationRouteData} from "astro"
    
    -function useRoute(route: RouteData) {
    +function useRoute(route: IntegrationRouteData) {
    
    }
    
  • #11941 b6a5f39 Thanks @Princesseuh! - Merges the output: 'hybrid' and output: 'static' configurations into one single configuration (now called 'static') that works the same way as the previous hybrid option.

    It is no longer necessary to specify output: 'hybrid' in your Astro config to use server-rendered pages. The new output: 'static' has this capability included. Astro will now automatically provide the ability to opt out of prerendering in your static site with no change to your output configuration required. Any page route or endpoint can include export const prerender = false to be server-rendered, while the rest of your site is statically-generated.

    If your project used hybrid rendering, you must now remove the output: 'hybrid' option from your Astro config as it no longer exists. However, no other changes to your project are required, and you should have no breaking changes. The previous 'hybrid' behavior is now the default, under a new name 'static'.

    If you were using the output: 'static' (default) option, you can continue to use it as before. By default, all of your pages will continue to be prerendered and you will have a completely static site. You should have no breaking changes to your project.

    import { defineConfig } from "astro/config";
    
    export default defineConfig({
    -  output: 'hybrid',
    });
    

    An adapter is still required to deploy an Astro project with any server-rendered pages. Failure to include an adapter will result in a warning in development and an error at build time.

  • #11788 7c0ccfc Thanks @ematipico! - Updates the default value of security.checkOrigin to true, which enables Cross-Site Request Forgery (CSRF) protection by default for pages rendered on demand.

    If you had previously configured security.checkOrigin: true, you no longer need this set in your Astro config. This is now the default and it is safe to remove.

    To disable this behavior and opt out of automatically checking that the “origin” header matches the URL sent by each request, you must explicitly set security.checkOrigin: false:

    export default defineConfig({
    +  security: {
    +    checkOrigin: false
    +  }
    })
    
  • #11825 560ef15 Thanks @bluwy! - Updates internal Shiki rehype plugin to highlight code blocks as hast (using Shiki's codeToHast() API). This allows a more direct Markdown and MDX processing, and improves the performance when building the project, but may cause issues with existing Shiki transformers.

    If you are using Shiki transformers passed to markdown.shikiConfig.transformers, you must make sure they do not use the postprocess hook as it no longer runs on code blocks in .md and .mdx files. (See the Shiki documentation on transformer hooks for more information).

    Code blocks in .mdoc files and <Code /> component do not use the internal Shiki rehype plugin and are unaffected.

  • #11826 7315050 Thanks @matthewp! - Deprecate Astro.glob

    The Astro.glob function has been deprecated in favor of Content Collections and import.meta.glob.

    Also consider using glob packages from npm, like fast-glob, especially if statically generating your site, as it is faster for most use-cases.

    The easiest path is to migrate to import.meta.glob like so:

    - const posts = Astro.glob('./posts/*.md');
    + const posts = Object.values(import.meta.glob('./posts/*.md', { eager: true }));
    
  • #12268 4e9a3ac Thanks @ematipico! - The command astro add vercel now updates the configuration file differently, and adds @astrojs/vercel as module to import.

    This is a breaking change because it requires the version 8.* of @astrojs/vercel.

  • #11741 6617491 Thanks @bluwy! - Removes internal JSX handling and moves the responsibility to the @astrojs/mdx package directly. The following exports are also now removed:

    • astro/jsx/babel.js
    • astro/jsx/component.js
    • astro/jsx/index.js
    • astro/jsx/renderer.js
    • astro/jsx/server.js
    • astro/jsx/transform-options.js

    If your project includes .mdx files, you must upgrade @astrojs/mdx to the latest version so that it doesn't rely on these entrypoints to handle your JSX.

  • #11782 9a2aaa0 Thanks @Princesseuh! - Makes the compiledContent property of Markdown content an async function, this change should fix underlying issues where sometimes when using a custom image service and images inside Markdown, Node would exit suddenly without any error message.

    ---
    import * as myPost from "../post.md";
    
    - const content = myPost.compiledContent();
    + const content = await myPost.compiledContent();
    ---
    
    <Fragment set:html={content} />
    
  • #11819 2bdde80 Thanks @bluwy! - Updates the Astro config loading flow to ignore processing locally-linked dependencies with Vite (e.g. npm link, in a monorepo, etc). Instead, they will be normally imported by the Node.js runtime the same way as other dependencies from node_modules.

    Previously, Astro would process locally-linked dependencies which were able to use Vite features like TypeScript when imported by the Astro config file.

    However, this caused confusion as integration authors may test against a package that worked locally, but not when published. This method also restricts using CJS-only dependencies because Vite requires the code to be ESM. Therefore, Astro's behaviour is now changed to ignore processing any type of dependencies by Vite.

    In most cases, make sure your locally-linked dependencies are built to JS before running the Astro project, and the config loading should work as before.

  • #11827 a83e362 Thanks @matthewp! - Prevent usage of astro:content in the client

    Usage of astro:content in the client has always been discouraged because it leads to all of your content winding up in your client bundle, and can possibly leaks secrets.

    This formally makes doing so impossible, adding to the previous warning with errors.

    In the future Astro might add APIs for client-usage based on needs.

  • #11979 423dfc1 Thanks @bluwy! - Bumps vite dependency to v6.0.0-beta.2. The version is pinned and will be updated as new Vite versions publish to prevent unhandled breaking changes. For the full list of Vite-specific changes, see its changelog.

  • #11859 3804711 Thanks @florian-lefebvre! - Changes the default tsconfig.json with better defaults, and makes src/env.d.ts optional

    Astro's default tsconfig.json in starter examples has been updated to include generated types and exclude your build output. This means that src/env.d.ts is only necessary if you have added custom type declarations or if you're not using a tsconfig.json file.

    Additionally, running astro sync no longer creates, nor updates, src/env.d.ts as it is not required for type-checking standard Astro projects.

    To update your project to Astro's recommended TypeScript settings, please add the following include and exclude properties to tsconfig.json:

    {
        "extends": "astro/tsconfigs/base",
    +    "include": [".astro/types.d.ts", "**/*"],
    +    "exclude": ["dist"]
    }
    
  • #11715 d74617c Thanks @Princesseuh! - Refactor the exported types from the astro module. There should normally be no breaking changes, but if you relied on some previously deprecated types, these might now have been fully removed.

    In most cases, updating your code to move away from previously deprecated APIs in previous versions of Astro should be enough to fix any issues.

  • #12551 abf9a89 Thanks @ematipico! - Refactors legacy content and data collections to use the Content Layer API glob() loader for better performance and to support backwards compatibility. Also introduces the legacy.collections flag for projects that are unable to update to the new behavior immediately.

    ⚠️ BREAKING CHANGE FOR LEGACY CONTENT COLLECTIONS ⚠️

    By default, collections that use the old types (content or data) and do not define a loader are now implemented under the hood using the Content Layer API's built-in glob() loader, with extra backward-compatibility handling.

    In order to achieve backwards compatibility with existing content collections, the following have been implemented:

    • a glob loader collection is defined, with patterns that match the previous handling (matches src/content/<collection name>/**/*.md and other content extensions depending on installed integrations, with underscore-prefixed files and folders ignored)
    • When used in the runtime, the entries have an ID based on the filename in the same format as legacy collections
    • A slug field is added with the same format as before
    • A render() method is added to the entry, so they can be called using entry.render()
    • getEntryBySlug is supported

    In order to achieve backwards compatibility with existing data collections, the following have been implemented:

    • a glob loader collection is defined, with patterns that match the previous handling (matches src/content/<collection name>/**/*{.json,.yaml} and other data extensions, with underscore-prefixed files and folders ignored)
    • Entries have an ID that is not slugified
    • getDataEntryById is supported

    While this backwards compatibility implementation is able to emulate most of the features of legacy collections, there are some differences and limitations that may cause breaking changes to existing collections:

    • In previous versions of Astro, collections would be generated for all folders in src/content/, even if they were not defined in src/content/config.ts. This behavior is now deprecated, and collections should always be defined in src/content/config.ts. For existing collections, these can just be empty declarations (e.g. const blog = defineCollection({})) and Astro will implicitly define your legacy collection for you in a way that is compatible with the new loading behavior.
    • The special layout field is not supported in Markdown collection entries. This property is intended only for standalone page files located in src/pages/ and not likely to be in your collection entries. However, if you were using this property, you must now create dynamic routes that include your page styling.
    • Sort order of generated collections is non-deterministic and platform-dependent. This means that if you are calling getCollection(), the order in which entries are returned may be different than before. If you need a specific order, you should sort the collection entries yourself.
    • image().refine() is not supported. If you need to validate the properties of an image you will need to do this at runtime in your page or component.
    • the key argument of getEntry(collection, key) is typed as string, rather than having types for every entry.

    A new legacy configuration flag legacy.collections is added for users that want to keep their current legacy (content and data) collections behavior (available in Astro v2 - v4), or who are not yet ready to update their projects:

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      legacy: {
        collections: true,
      },
    });
    

    When set, no changes to your existing collections are necessary, and the restrictions on storing both new and old collections continue to exist: legacy collections (only) must continue to remain in src/content/, while new collections using a loader from the Content Layer API are forbidden in that folder.

  • #11660 e90f559 Thanks @bluwy! - Fixes attribute rendering for non-boolean HTML attributes with boolean values to match proper attribute handling in browsers.

    Previously, non-boolean attributes may not have included their values when rendered to HTML. In Astro v5.0, the values are now explicitly rendered as ="true" or ="false"

    In the following .astro examples, only allowfullscreen is a boolean attribute:

    <!-- src/pages/index.astro --><!-- `allowfullscreen` is a boolean attribute -->
    <p allowfullscreen={true}></p>
    <p allowfullscreen={false}></p>
    
    <!-- `inherit` is *not* a boolean attribute -->
    <p inherit={true}></p>
    <p inherit={false}></p>
    
    <!-- `data-*` attributes are not boolean attributes -->
    <p data-light={true}></p>
    <p data-light={false}></p>
    

    Astro v5.0 now preserves the full data attribute with its value when rendering the HTML of non-boolean attributes:

      <p allowfullscreen></p>
      <p></p>
    
      <p inherit="true"></p>
    - <p inherit></p>
    + <p inherit="false"></p>
    
    - <p data-light></p>
    + <p data-light="true"></p>
    - <p></p>
    + <p data-light="false"></p>
    

    If you rely on attribute values, for example to locate elements or to conditionally render, update your code to match the new non-boolean attribute values:

    - el.getAttribute('inherit') === ''
    + el.getAttribute('inherit') === 'false'
    
    - el.hasAttribute('data-light')
    + el.dataset.light === 'true'
    
  • #11770 cfa6a47 Thanks @Princesseuh! - Removed support for the Squoosh image service. As the underlying library libsquoosh is no longer maintained, and the image service sees very little usage we have decided to remove it from Astro.

    Our recommendation is to use the base Sharp image service, which is more powerful, faster, and more actively maintained.

    - import { squooshImageService } from "astro/config";
    import { defineConfig } from "astro/config";
    
    export default defineConfig({
    -  image: {
    -    service: squooshImageService()
    -  }
    });
    

    If you are using this service, and cannot migrate to the base Sharp image service, a third-party extraction of the previous service is available here: https://github.com/Princesseuh/astro-image-service-squoosh

  • #12231 90ae100 Thanks @bluwy! - Updates the automatic charset=utf-8 behavior for Markdown pages, where instead of responding with charset=utf-8 in the Content-Type header, Astro will now automatically add the <meta charset="utf-8"> tag instead.

    This behaviour only applies to Markdown pages (.md or similar Markdown files located within src/pages/) that do not use Astro's special layout frontmatter property. It matches the rendering behaviour of other non-content pages, and retains the minimal boilerplate needed to write with non-ASCII characters when adding individual Markdown pages to your site.

    If your Markdown pages use the layout frontmatter property, then HTML encoding will be handled by the designated layout component instead, and the <meta charset="utf-8"> tag will not be added to your page by default.

    If you require charset=utf-8 to render your page correctly, make sure that your layout components contain the <meta charset="utf-8"> tag. You may need to add this if you have not already done so.

  • #11714 8a53517 Thanks @matthewp! - Remove support for functionPerRoute

    This change removes support for the functionPerRoute option both in Astro and @astrojs/vercel.

    This option made it so that each route got built as separate entrypoints so that they could be loaded as separate functions. The hope was that by doing this it would decrease the size of each function. However in practice routes use most of the same code, and increases in function size limitations made the potential upsides less important.

    Additionally there are downsides to functionPerRoute, such as hitting limits on the number of functions per project. The feature also never worked with some Astro features like i18n domains and request rewriting.

    Given this, the feature has been removed from Astro.

  • #11864 ee38b3a Thanks @ematipico! - ### [changed]: RouteData.distURL is now an array In Astro v4.x, RouteData.distURL was undefined or a URL

    Astro v5.0, RouteData.distURL is undefined or an array of URL. This was a bug, because a route can generate multiple files on disk, especially when using dynamic routes such as [slug] or [...slug].

    What should I do?

    Update your code to handle RouteData.distURL as an array.

    if (route.distURL) {
    -  if (route.distURL.endsWith('index.html')) {
    -    // do something
    -  }
    +  for (const url of route.distURL) {
    +    if (url.endsWith('index.html')) {
    +      // do something
    +    }
    +  }
    }
    
  • #11253 4e5cc5a Thanks @kevinzunigacuellar! - Changes the data returned for page.url.current, page.url.next, page.url.prev, page.url.first and page.url.last to include the value set for base in your Astro config.

    Previously, you had to manually prepend your configured value for base to the URL path. Now, Astro automatically includes your base value in next and prev URLs.

    If you are using the paginate() function for "previous" and "next" URLs, remove any existing base value as it is now added for you:

    ---
    export async function getStaticPaths({ paginate }) {
      const astronautPages = [{
        astronaut: 'Neil Armstrong',
      }, {
        astronaut: 'Buzz Aldrin',
      }, {
        astronaut: 'Sally Ride',
      }, {
        astronaut: 'John Glenn',
      }];
      return paginate(astronautPages, { pageSize: 1 });
    }
    const { page } = Astro.props;
    // `base: /'docs'` configured in `astro.config.mjs`
    - const prev = "/docs" + page.url.prev;
    + const prev = page.url.prev;
    ---
    <a id="prev" href={prev}>Back</a>
    
  • #12079 7febf1f Thanks @ematipico! - params passed in getStaticPaths are no longer automatically decoded.

    [changed]: params aren't decoded anymore.

    In Astro v4.x, params in were automatically decoded using decodeURIComponent.

    Astro v5.0 doesn't automatically decode params in getStaticPaths anymore, so you'll need to manually decode them yourself if needed

    What should I do?

    If you were relying on the automatic decode, you'll need to manually decode it using decodeURI.

    Note that the use of decodeURIComponent) is discouraged for getStaticPaths because it decodes more characters than it should, for example /, ?, # and more.

    ---
    export function getStaticPaths() {
      return [
    +    { params: { id: decodeURI("%5Bpage%5D") } },
    -    { params: { id: "%5Bpage%5D" } },
      ]
    }
    
    const { id } = Astro.params;
    ---
    

Minor Changes

  • #11941 b6a5f39 Thanks @Princesseuh! - Adapters can now specify the build output type they're intended for using the adapterFeatures.buildOutput property. This property can be used to always generate a server output, even if the project doesn't have any server-rendered pages.

    {
      'astro:config:done': ({ setAdapter, config }) => {
        setAdapter({
          name: 'my-adapter',
          adapterFeatures: {
            buildOutput: 'server',
          },
        });
      },
    }
    

    If your adapter specifies buildOutput: 'static', and the user's project contains server-rendered pages, Astro will warn in development and error at build time. Note that a hybrid output, containing both static and server-rendered pages, is considered to be a server output, as a server is required to serve the server-rendered pages.

  • #12067 c48916c Thanks @stramel! - Adds experimental support for built-in SVG components.

    This feature allows you to import SVG files directly into your Astro project as components. By default, Astro will inline the SVG content into your HTML output.

    To enable this feature, set experimental.svg to true in your Astro config:

    {
      experimental: {
        svg: true,
      },
    }
    

    To use this feature, import an SVG file in your Astro project, passing any common SVG attributes to the imported component. Astro also provides a size attribute to set equal height and width properties:

    ---
    import Logo from './path/to/svg/file.svg';
    ---
    
    <Logo size={24} />
    

    For a complete overview, and to give feedback on this experimental API, see the Feature RFC.

  • #12226 51d13e2 Thanks @ematipico! - The following renderer fields and integration fields now accept URL as a type:

    Renderers:

    • AstroRenderer.clientEntrpoint
    • AstroRenderer.serverEntrypoint

    Integrations:

    • InjectedRoute.entrypoint
    • AstroIntegrationMiddleware.entrypoint
    • DevToolbarAppEntry.entrypoint
  • #12323 c280655 Thanks @bluwy! - Updates to Vite 6.0.0-beta.6

  • #12539 827093e Thanks @bluwy! - Drops node 21 support

  • #12243 eb41d13 Thanks @florian-lefebvre! - Improves defineConfig type safety. TypeScript will now error if a group of related configuration options do not have consistent types. For example, you will now see an error if your language set for i18n.defaultLocale is not one of the supported locales specified in i18n.locales.

  • #12329 8309c61 Thanks @florian-lefebvre! - Adds a new astro:routes:resolved hook to the Integration API. Also update the astro:build:done hook by deprecating routes and adding a new assets map.

    When building an integration, you can now get access to routes inside the astro:routes:resolved hook:

    const integration = () => {
      return {
        name: 'my-integration',
        hooks: {
          'astro:routes:resolved': ({ routes }) => {
            console.log(routes);
          },
        },
      };
    };
    

    This hook runs before astro:config:done, and whenever a route changes in development.

    The routes array from astro:build:done is now deprecated, and exposed properties are now available on astro:routes:resolved, except for distURL. For this, you can use the newly exposed assets map:

    const integration = () => {
    +    let routes
        return {
            name: 'my-integration',
            hooks: {
    +            'astro:routes:resolved': (params) => {
    +                routes = params.routes
    +            },
                'astro:build:done': ({
    -                routes
    +                assets
                }) => {
    +                for (const route of routes) {
    +                    const distURL = assets.get(route.pattern)
    +                    if (distURL) {
    +                        Object.assign(route, { distURL })
    +                    }
    +                }
                    console.log(routes)
                }
            }
        }
    }
    
  • #11911 c3dce83 Thanks @ascorbic! - The Content Layer API introduced behind a flag in 4.14.0 is now stable and ready for use in Astro v5.0.

    The new Content Layer API builds upon content collections, taking them beyond local files in src/content/ and allowing you to fetch content from anywhere, including remote APIs. These new collections work alongside your existing content collections, and you can migrate them to the new API at your own pace. There are significant improvements to performance with large collections of local files. For more details, see the Content Layer RFC.

    If you previously used this feature, you can now remove the experimental.contentLayer flag from your Astro config:

    // astro.config.mjs
    import { defineConfig } from 'astro'
    
    export default defineConfig({
    -  experimental: {
    -    contentLayer: true
    -  }
    })
    

    Loading your content

    The core of the new Content Layer API is the loader, a function that fetches content from a source and caches it in a local data store. Astro 4.14 ships with built-in glob() and file() loaders to handle your local Markdown, MDX, Markdoc, and JSON files:

    // src/content/config.ts
    import { defineCollection, z } from 'astro:content';
    import { glob } from 'astro/loaders';
    
    const blog = defineCollection({
      // The ID is a slug generated from the path of the file relative to `base`
      loader: glob({ pattern: '**/*.md', base: './src/data/blog' }),
      schema: z.object({
        title: z.string(),
        description: z.string(),
        publishDate: z.coerce.date(),
      }),
    });
    
    export const collections = { blog };
    

    You can then query using the existing content collections functions, and use a simplified render() function to display your content:

    ---
    import { getEntry, render } from 'astro:content';
    
    const post = await getEntry('blog', Astro.params.slug);
    
    const { Content } = await render(entry);
    ---
    
    <Content />
    

    Creating a loader

    You're not restricted to the built-in loaders we hope you'll try building your own. You can fetch content from anywhere and return an array of entries:

    // src/content/config.ts
    const countries = defineCollection({
      loader: async () => {
        const response = await fetch('https://restcountries.com/v3.1/all');
        const data = await response.json();
        // Must return an array of entries with an id property,
        // or an object with IDs as keys and entries as values
        return data.map((country) => ({
          id: country.cca3,
          ...country,
        }));
      },
      // optionally add a schema to validate the data and make it type-safe for users
      // schema: z.object...
    });
    
    export const collections = { countries };
    

    For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading, and gives full access to the data store. It also allows a loader to define its own schema, including generating it dynamically based on the source API. See the the Content Layer API RFC for more details.

    Sharing your loaders

    Loaders are better when they're shared. You can create a package that exports a loader and publish it to npm, and then anyone can use it on their site. We're excited to see what the community comes up with! To get started, take a look at some examples. Here's how to load content using an RSS/Atom feed loader:

    // src/content/config.ts
    import { defineCollection } from 'astro:content';
    import { feedLoader } from '@ascorbic/feed-loader';
    
    const podcasts = defineCollection({
      loader: feedLoader({
        url: 'https://feeds.99percentinvisible.org/99percentinvisible',
      }),
    });
    
    export const collections = { podcasts };
    

    To learn more, see the Content Layer RFC.

  • #11980 a604a0c Thanks @matthewp! - ViewTransitions component renamed to ClientRouter

    The <ViewTransitions /> component has been renamed to <ClientRouter />. There are no other changes than the name. The old name will continue to work in Astro 5.x, but will be removed in 6.0.

    This change was done to clarify the role of the component within Astro's View Transitions support. Astro supports View Transitions APIs in a few different ways, and renaming the component makes it more clear that the features you get from the ClientRouter component are slightly different from what you get using the native CSS-based MPA router.

    We still intend to maintain the ClientRouter as before, and it's still important for use-cases that the native support doesn't cover, such as persisting state between pages.

  • #11875 a8a3d2c Thanks @florian-lefebvre! - Adds a new property isPrerendered to the globals Astro and APIContext . This boolean value represents whether or not the current page is prerendered:

    ---
    // src/pages/index.astro
    
    export const prerender = true;
    ---
    
    // src/middleware.js
    
    export const onRequest = (ctx, next) => {
      console.log(ctx.isPrerendered); // it will log true
      return next();
    };
    
  • #12047 21b5e80 Thanks @rgodha24! - Adds a new optional parser property to the built-in file() loader for content collections to support additional file types such as toml and csv.

    The file() loader now accepts a second argument that defines a parser function. This allows you to specify a custom parser (e.g. toml.parse or csv-parse) to create a collection from a file's contents. The file() loader will automatically detect and parse JSON and YAML files (based on their file extension) with no need for a parser.

    This works with any type of custom file formats including csv and toml. The following example defines a content collection dogs using a .toml file.

    [[dogs]]
    id = "..."
    age = "..."
    
    [[dogs]]
    id = "..."
    age = "..."
    

    After importing TOML's parser, you can load the dogs collection into your project by passing both a file path and parser to the file() loader.

    import { defineCollection } from "astro:content"
    import { file } from "astro/loaders"
    import { parse as parseToml } from "toml"
    
    const dogs = defineCollection({
      loader: file("src/data/dogs.toml", { parser: (text) => parseToml(text).dogs }),
      schema: /* ... */
    })
    
    // it also works with CSVs!
    import { parse as parseCsv } from "csv-parse/sync";
    
    const cats = defineCollection({
      loader: file("src/data/cats.csv", { parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true })})
    });
    

    The parser argument also allows you to load a single collection from a nested JSON document. For example, this JSON file contains multiple collections:

    { "dogs": [{}], "cats": [{}] }
    

    You can separate these collections by passing a custom parser to the file() loader like so:

    const dogs = defineCollection({
      loader: file('src/data/pets.json', { parser: (text) => JSON.parse(text).dogs }),
    });
    const cats = defineCollection({
      loader: file('src/data/pets.json', { parser: (text) => JSON.parse(text).cats }),
    });
    

    And it continues to work with maps of id to data

    bubbles:
      breed: 'Goldfish'
      age: 2
    finn:
      breed: 'Betta'
      age: 1
    
    const fish = defineCollection({
      loader: file('src/data/fish.yaml'),
      schema: z.object({ breed: z.string(), age: z.number() }),
    });
    
  • #11698 05139ef Thanks @ematipico! - Adds a new property to the globals Astro and APIContext called routePattern. The routePattern represents the current route (component) that is being rendered by Astro. It's usually a path pattern will look like this: blog/[slug]:

    ---
    // src/pages/blog/[slug].astro
    const route = Astro.routePattern;
    console.log(route); // it will log "blog/[slug]"
    ---
    
    // src/pages/index.js
    
    export const GET = (ctx) => {
      console.log(ctx.routePattern); // it will log src/pages/index.js
      return new Response.json({ loreum: 'ipsum' });
    };
    
  • #11941 b6a5f39 Thanks @Princesseuh! - Adds a new buildOutput property to the astro:config:done hook returning the build output type.

    This can be used to know if the user's project will be built as a static site (HTML files), or a server-rendered site (whose exact output depends on the adapter).

  • #12377 af867f3 Thanks @ascorbic! - Adds experimental support for automatic responsive images

    This feature is experimental and may change in future versions. To enable it, set experimental.responsiveImages to true in your astro.config.mjs file.

    {
       experimental: {
          responsiveImages: true,
       },
    }
    

    When this flag is enabled, you can pass a layout prop to any <Image /> or <Picture /> component to create a responsive image. When a layout is set, images have automatically generated srcset and sizes attributes based on the image's dimensions and the layout type. Images with responsive and full-width layouts will have styles applied to ensure they resize according to their container.

    ---
    import { Image, Picture } from 'astro:assets';
    import myImage from '../assets/my_image.png';
    ---
    
    <Image
      src={myImage}
      alt="A description of my image."
      layout="responsive"
      width={800}
      height={600}
    />
    <Picture
      src={myImage}
      alt="A description of my image."
      layout="full-width"
      formats={['avif', 'webp', 'jpeg']}
    />
    

    This <Image /> component will generate the following HTML output:

    <img
      src="/_astro/my_image.hash3.webp"
      srcset="
        /_astro/my_image.hash1.webp  640w,
        /_astro/my_image.hash2.webp  750w,
        /_astro/my_image.hash3.webp  800w,
        /_astro/my_image.hash4.webp  828w,
        /_astro/my_image.hash5.webp 1080w,
        /_astro/my_image.hash6.webp 1280w,
        /_astro/my_image.hash7.webp 1600w
      "
      alt="A description of my image"
      sizes="(min-width: 800px) 800px, 100vw"
      loading="lazy"
      decoding="async"
      fetchpriority="auto"
      width="800"
      height="600"
      style="--w: 800; --h: 600; --fit: cover; --pos: center;"
      data-astro-image="responsive"
    />
    

    Responsive image properties

    These are additional properties available to the <Image /> and <Picture /> components when responsive images are enabled:

    • layout: The layout type for the image. Can be responsive, fixed, full-width or none. Defaults to value of image.experimentalLayout.
    • fit: Defines how the image should be cropped if the aspect ratio is changed. Values match those of CSS object-fit. Defaults to cover, or the value of image.experimentalObjectFit if set.
    • position: Defines the position of the image crop if the aspect ratio is changed. Values match those of CSS object-position. Defaults to center, or the value of image.experimentalObjectPosition if set.
    • priority: If set, eagerly loads the image. Otherwise images will be lazy-loaded. Use this for your largest above-the-fold image. Defaults to false.

    Default responsive image settings

    You can enable responsive images for all <Image /> and <Picture /> components by setting image.experimentalLayout with a default value. This can be overridden by the layout prop on each component.

    Example:

    {
        image: {
          // Used for all `<Image />` and `<Picture />` components unless overridden
          experimentalLayout: 'responsive',
        },
        experimental: {
          responsiveImages: true,
        },
    }
    
    ---
    import { Image } from 'astro:assets';
    import myImage from '../assets/my_image.png';
    ---
    
    <Image src={myImage} alt="This will use responsive layout" width={800} height={600} />
    
    <Image src={myImage} alt="This will use full-width layout" layout="full-width" />
    
    <Image src={myImage} alt="This will disable responsive images" layout="none" />
    

    For a complete overview, and to give feedback on this experimental API, see the Responsive Images RFC.

  • #12150 93351bc Thanks @bluwy! - Adds support for passing values other than "production" or "development" to the --mode flag (e.g. "staging", "testing", or any custom value) to change the value of import.meta.env.MODE or the loaded .env file. This allows you take advantage of Vite's mode feature.

    Also adds a new --devOutput flag for astro build that will output a development-based build.

    Note that changing the mode does not change the kind of code transform handled by Vite and Astro:

    • In astro dev, Astro will transform code with debug information.
    • In astro build, Astro will transform code with the most optimized output and removes debug information.
    • In astro build --devOutput (new flag), Astro will transform code with debug information like in astro dev.

    This enables various usecases like:

    # Run the dev server connected to a "staging" API
    astro dev --mode staging
    
    # Build a site that connects to a "staging" API
    astro build --mode staging
    
    # Build a site that connects to a "production" API with additional debug information
    astro build --devOutput
    
    # Build a site that connects to a "testing" API
    astro build --mode testing
    

    The different modes can be used to load different .env files, e.g. .env.staging or .env.production, which can be customized for each environment, for example with different API_URL environment variable values.

  • #12510 14feaf3 Thanks @bholmesdev! - Changes the generated URL query param from _astroAction to _action when submitting a form using Actions. This avoids leaking the framework name into the URL bar, which may be considered a security issue.

  • #11806 f7f2338 Thanks @Princesseuh! - The value of the different properties on supportedAstroFeatures for adapters can now be objects, with a support and message properties. The content of the message property will be shown in the Astro CLI when the adapter is not compatible with the feature, allowing one to give a better informational message to the user.

    This is notably useful with the new limited value, to explain to the user why support is limited.

  • #12071 61d248e Thanks @Princesseuh! - astro add no longer automatically sets output: 'server'. Since the default value of output now allows for server-rendered pages, it no longer makes sense to default to full server builds when you add an adapter

  • #11955 d813262 Thanks @matthewp! - Server Islands introduced behind an experimental flag in v4.12.0 is no longer experimental and is available for general use.

    Server islands are Astro's solution for highly cacheable pages of mixed static and dynamic content. They allow you to specify components that should run on the server, allowing the rest of the page to be more aggressively cached, or even generated statically.

    Turn any .astro component into a server island by adding the server:defer directive and optionally, fallback placeholder content. It will be rendered dynamically at runtime outside the context of the rest of the page, allowing you to add longer cache headers for the pages, or even prerender them.

    ---
    import Avatar from '../components/Avatar.astro';
    import GenericUser from '../components/GenericUser.astro';
    ---
    
    <header>
      <h1>Page Title</h1>
      <div class="header-right">
        <Avatar server:defer>
          <GenericUser slot="fallback" />
        </Avatar>
      </div>
    </header>
    

    If you were previously using this feature, please remove the experimental flag from your Astro config:

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

    If you have been waiting for stabilization before using server islands, you can now do so.

    Please see the server island documentation for more about this feature.

  • #12373 d10f918 Thanks @bholmesdev! - Changes the default behavior for Astro Action form requests to a standard POST submission.

    In Astro 4.x, actions called from an HTML form would trigger a redirect with the result forwarded using cookies. This caused issues for large form errors and return values that exceeded the 4 KB limit of cookie-based storage.

    Astro 5.0 now renders the result of an action as a POST result without any forwarding. This will introduce a "confirm form resubmission?" dialog when a user attempts to refresh the page, though it no longer imposes a 4 KB limit on action return value.

    Customize form submission behavior

    If you prefer to address the "confirm form resubmission?" dialog on refresh, or to preserve action results across sessions, you can now customize action result handling from middleware.

    We recommend using a session storage provider as described in our Netlify Blob example. However, if you prefer the cookie forwarding behavior from 4.X and accept the 4 KB size limit, you can implement the pattern as shown in this sample snippet:

    // src/middleware.ts
    import { defineMiddleware } from 'astro:middleware';
    import { getActionContext } from 'astro:actions';
    
    export const onRequest = defineMiddleware(async (context, next) => {
      // Skip requests for prerendered pages
      if (context.isPrerendered) return next();
    
      const { action, setActionResult, serializeActionResult } = getActionContext(context);
    
      // If an action result was forwarded as a cookie, set the result
      // to be accessible from `Astro.getActionResult()`
      const payload = context.cookies.get('ACTION_PAYLOAD');
      if (payload) {
        const { actionName, actionResult } = payload.json();
        setActionResult(actionName, actionResult);
        context.cookies.delete('ACTION_PAYLOAD');
        return next();
      }
    
      // If an action was called from an HTML form action,
      // call the action handler and redirect with the result as a cookie.
      if (action?.calledFrom === 'form') {
        const actionResult = await action.handler();
    
        context.cookies.set('ACTION_PAYLOAD', {
          actionName: action.name,
          actionResult: serializeActionResult(actionResult),
        });
    
        if (actionResult.error) {
          // Redirect back to the previous page on error
          const referer = context.request.headers.get('Referer');
          if (!referer) {
            throw new Error('Internal: Referer unexpectedly missing from Action POST request.');
          }
          return context.redirect(referer);
        }
        // Redirect to the destination page on success
        return context.redirect(context.originPathname);
      }
    
      return next();
    });
    
  • #12475 3f02d5f Thanks @ascorbic! - Changes the default content config location from src/content/config.* to src/content.config.*.

    The previous location is still supported, and is required if the legacy.collections flag is enabled.

  • #11963 0a1036e Thanks @florian-lefebvre! - Adds a new createCodegenDir() function to the astro:config:setup hook in the Integrations API

    In 4.14, we introduced the injectTypes utility on the astro:config:done hook. It can create .d.ts files and make their types available to user's projects automatically. Under the hood, it creates a file in <root>/.astro/integrations/<normalized_integration_name>.

    While the .astro directory has always been the preferred place to write code generated files, it has also been prone to mistakes. For example, you can write a .astro/types.d.ts file, breaking Astro types. Or you can create a file that overrides a file created by another integration.

    In this release, <root>/.astro/integrations/<normalized_integration_name> can now be retrieved in the astro:config:setup hook by calling createCodegenDir(). It allows you to have a dedicated folder, avoiding conflicts with another integration or Astro itself. This directory is created by calling this function so it's safe to write files to it directly:

    import { writeFileSync } from 'node:fs';
    
    const integration = {
      name: 'my-integration',
      hooks: {
        'astro:config:setup': ({ createCodegenDir }) => {
          const codegenDir = createCodegenDir();
          writeFileSync(new URL('cache.json', codegenDir), '{}', 'utf-8');
        },
      },
    };
    
  • #12379 94f4fe8 Thanks @Princesseuh! - Adds a new components exported from astro/components: Welcome, to be used by the new Basics template

  • #11806 f7f2338 Thanks @Princesseuh! - Adds a new limited value for the different properties of supportedAstroFeatures for adapters, which indicates that the adapter is compatible with the feature, but with some limitations. This is useful for adapters that support a feature, but not in all cases or with all options.

  • #11925 74722cb Thanks @florian-lefebvre! - Updates astro/config import to reference astro/client types

    When importing astro/config, types from astro/client will be made automatically available to your project. If your project tsconfig.json changes how references behave, you'll still have access to these types after running astro sync.

  • #12081 8679954 Thanks @florian-lefebvre! - Removes the experimental contentCollectionsCache introduced in 3.5.0.

    Astro Content Layer API independently solves some of the caching and performance issues with legacy content collections that this strategy attempted to address. This feature has been replaced with continued work on improvements to the content layer. If you were using this experimental feature, you must now remove the flag from your Astro config as it no longer exists:

    export default defineConfig({
        experimental: {
    -        contentCollectionsCache: true
        }
    })
    

    The cacheManifest boolean argument is no longer passed to the astro:build:done integration hook:

    const integration = {
        name: "my-integration",
        hooks: {
            "astro:build:done": ({
    -            cacheManifest,
                logger
            }) => {}
        }
    }
    

Patch Changes

  • #12565 97f413f Thanks @ascorbic! - Fixes a bug where content types were not generated when first running astro dev unless src/content exists

  • #11987 bf90a53 Thanks @florian-lefebvre! - render() signature now takes renderOptions as 2nd argument

    The signature for app.render() has changed, and the second argument is now an options object called renderOptions with more options for customizing rendering.

    The renderOptions are:

    • addCookieHeader: Determines whether Astro will set the Set-Cookie header, otherwise the adapter is expected to do so itself.
    • clientAddress: The client IP address used to set Astro.clientAddress.
    • locals: An object of locals that's set to Astro.locals.
    • routeData: An object specifying the route to use.
  • #12522 33b0e30 Thanks @ascorbic! - Fixes a bug where content config was ignored if it was outside of content dir and has a parent dir with an underscore

  • #12424 4364bff Thanks @ematipico! - Fixes an issue where an incorrect usage of Astro actions was lost when porting the fix from v4 to v5

  • #12438 c8f877c Thanks @ascorbic! - Fixes a bug where legacy content types were generated for content layer collections if they were in the content directory

  • #12035 325a57c Thanks @ascorbic! - Correctly parse values returned from inline loader

  • #11960 4410130 Thanks @ascorbic! - Fixes an issue where the refresh context data was not passed correctly to content layer loaders

  • #11878 334948c Thanks @ascorbic! - Adds a new function refreshContent to the astro:server:setup hook that allows integrations to refresh the content layer. This can be used, for example, to register a webhook endpoint during dev, or to open a socket to a CMS to listen for changes.

    By default, refreshContent will refresh all collections. You can optionally pass a loaders property, which is an array of loader names. If provided, only collections that use those loaders will be refreshed. For example, A CMS integration could use this property to only refresh its own collections.

    You can also pass a context object to the loaders. This can be used to pass arbitrary data, such as the webhook body, or an event from the websocket.

     {
        name: 'my-integration',
        hooks: {
            'astro:server:setup': async ({ server, refreshContent }) => {
                server.middlewares.use('/_refresh', async (req, res) => {
                    if(req.method !== 'POST') {
                      res.statusCode = 405
                      res.end('Method Not Allowed');
                      return
                    }
                    let body = '';
                    req.on('data', chunk => {
                        body += chunk.toString();
                    });
                    req.on('end', async () => {
                        try {
                            const webhookBody = JSON.parse(body);
                            await refreshContent({
                              context: { webhookBody },
                              loaders: ['my-loader']
                            });
                            res.writeHead(200, { 'Content-Type': 'application/json' });
                            res.end(JSON.stringify({ message: 'Content refreshed successfully' }));
                        } catch (error) {
                            res.writeHead(500, { 'Content-Type': 'application/json' });
                            res.end(JSON.stringify({ error: 'Failed to refresh content: ' + error.message }));
                        }
                    });
                });
            }
        }
    }
    
  • #11991 d7a396c Thanks @matthewp! - Update error link to on-demand rendering guide

  • #12127 55e9cd8 Thanks @ascorbic! - Prevents Vite emitting an error when restarting itself

  • #12516 cb9322c Thanks @stramel! - Handle multiple root nodes on SVG files

  • #11974 60211de Thanks @ascorbic! - Exports the RenderResult type

  • #12578 07b9ca8 Thanks @WesSouza! - Explicitly import index.ts to fix types when moduleResolution is NodeNext

  • #11791 9393243 Thanks @bluwy! - Updates Astro's default <script> rendering strategy and removes the experimental.directRenderScript option as this is now the default behavior: scripts are always rendered directly. This new strategy prevents scripts from being executed in pages where they are not used.

    Scripts will directly render as declared in Astro files (including existing features like TypeScript, importing node_modules, and deduplicating scripts). You can also now conditionally render scripts in your Astro file.

    However, this means scripts are no longer hoisted to the <head>, multiple scripts on a page are no longer bundled together, and the <script> tag may interfere with the CSS styling.

    As this is a potentially breaking change to your script behavior, please review your <script> tags and ensure that they behave as expected.

  • #12011 cfdaab2 Thanks @ArmandPhilippot! - Fixes a type and an example in documenting the security.checkOrigin property of Astro config.

  • #12168 1cd3085 Thanks @ascorbic! - Allows "slug" as a field in content layer data

  • #12302 7196c24 Thanks @ematipico! - Fixes an issue where the origin check middleware run for prendered pages

  • #12341 c1786d6 Thanks @ematipico! - Fixes and issue where Astro.currentLocale always returned the default locale when consumed inside a server island.

  • #11732 4cd6c43 Thanks @matthewp! - Use GET requests with preloading for Server Islands

    Server Island requests include the props used to render the island as well as any slots passed in (excluding the fallback slot). Since browsers have a max 4mb URL length we default to using a POST request to avoid overflowing this length.

    However in reality most usage of Server Islands are fairly isolated and won't exceed this limit, so a GET request is possible by passing this same information via search parameters.

    Using GET means we can also include a <link rel="preload"> tag to speed up the request.

    This change implements this, with safe fallback to POST.

  • #11952 50a0146 Thanks @ascorbic! - Adds support for array patterns in the built-in glob() content collections loader

    The glob loader can now accept an array of multiple patterns as well as string patterns. This allows you to more easily combine multiple patterns into a single collection, and also means you can use negative matches to exclude files from the collection.

    const probes = defineCollection({
      // Load all markdown files in the space-probes directory, except for those that start with "voyager-"
      loader: glob({ pattern: ['*.md', '!voyager-*'], base: 'src/data/space-probes' }),
      schema: z.object({
        name: z.string(),
        type: z.enum(['Space Probe', 'Mars Rover', 'Comet Lander']),
        launch_date: z.date(),
        status: z.enum(['Active', 'Inactive', 'Decommissioned']),
        destination: z.string(),
        operator: z.string(),
        notable_discoveries: z.array(z.string()),
      }),
    });
    
  • #12022 ddc3a08 Thanks @Princesseuh! - Properly handle including trailing slash on the image endpoint route based on the trailingSlash config

  • #12169 15fa9ba Thanks @ematipico! - Fixes a bug where configured redirects were incorrectly constructed when reading the file system.

    This caused an issue where configuring a redirect in astro.config.mjs like { /old: /new }, failed to trigger the correct redirect in the dev server.

  • #11914 b5d827b Thanks @ascorbic! - Exports types for all LoaderContext properties from astro/loaders to make it easier to use them in custom loaders. The ScopedDataStore interface (which was previously internal) is renamed to DataStore, to reflect the fact that it's the only public API for the data store.

  • #12270 25192a0 Thanks @ematipico! - Fixes a bug where the params weren't correctly computed when rendering URLs with non-English characters

  • #11927 5b4e3ab Thanks @florian-lefebvre! - Updates the env configuration reference docs to include a full API reference for envField.

  • #12591 b731b3d Thanks @ascorbic! - Fixes a bug where a catchall route would match an image endpoint request

  • #12073 acf264d Thanks @bluwy! - Replaces ora with yocto-spinner

  • #12339 bdb75a8 Thanks @ematipico! - Adds an error when Astro.rewrite() is used to rewrite an on-demand route with a static route when using the "server" output.

    This is a forbidden rewrite because Astro can't retrieve the emitted static route at runtime. This route is served by the hosting platform, and not Astro itself.

  • #12511 d023682 Thanks @stramel! - Fix SVG Component sprite references

  • #12486 dc3d842 Thanks @matthewp! - Call server island early so it can set headers

  • #12016 837ee3a Thanks @matthewp! - Fixes actions with large amount of validation errors

  • #11943 fa4671c Thanks @sarah11918! - Updates error messages that assume content collections are located in src/content/ with more generic language

  • #12030 10a756a Thanks @ascorbic! - Resolves image paths in content layer with initial slash as project-relative

    When using the image() schema helper, previously paths with an initial slash were treated as public URLs. This was to match the behavior of markdown images. However this is a change from before, where paths with an initial slash were treated as project-relative. This change restores the previous behavior, so that paths with an initial slash are treated as project-relative.

  • #12009 f10a3b7 Thanks @matthewp! - Fixes use of Vitest with Astro 5

  • #12075 a19530e Thanks @bluwy! - Parses frontmatter ourselves

  • #12552 15f000c Thanks @avanderbergh! - Fixed an issue where modifying the Request.headers prototype during prerendering caused a build error. Removed conflicting value and writable properties from the headers descriptor to prevent Invalid property descriptor errors.

  • #12070 9693ad4 Thanks @ematipico! - Fixes an issue where the check origin middleware was incorrectly injected when the build output was "static"

  • #12169 15fa9ba Thanks @ematipico! - Fixes a bug where the dev server was not providing a consistent user experience for configured redirects.

    With the fix, when you configure a redirect in astro.config.mjs like this { /old: "/new" }, the dev server return an HTML response that matches the one emitted by a static build.

  • Updated dependencies [3ab3b4e, 5608338, 827093e, 560ef15, 83a2a64, 3ab3b4e, a19530e, 1dc8f5e]:

    • @astrojs/markdown-remark@6.0.0
    • @astrojs/telemetry@3.2.0
    • @astrojs/internal-helpers@0.4.2

5.0.0-beta.12

Major Changes

Minor Changes

Patch Changes

  • Updated dependencies [827093e]:
    • @astrojs/telemetry@3.2.0-beta.0
    • @astrojs/markdown-remark@6.0.0-beta.3

5.0.0-beta.11

Minor Changes

  • #12510 14feaf3 Thanks @bholmesdev! - Changes the generated URL query param from _astroAction to _action when submitting a form using Actions. This avoids leaking the framework name into the URL bar, which may be considered a security issue.

Patch Changes

5.0.0-beta.10

Patch Changes

5.0.0-beta.9

Minor Changes

  • #12067 c48916c Thanks @stramel! - Adds experimental support for built-in SVG components.

    This feature allows you to import SVG files directly into your Astro project as components. By default, Astro will inline the SVG content into your HTML output.

    To enable this feature, set experimental.svg to true in your Astro config:

    {
      experimental: {
        svg: true,
      },
    }
    

    To use this feature, import an SVG file in your Astro project, passing any common SVG attributes to the imported component. Astro also provides a size attribute to set equal height and width properties:

    ---
    import Logo from './path/to/svg/file.svg';
    ---
    
    <Logo size={24} />
    

    For a complete overview, and to give feedback on this experimental API, see the Feature RFC.

  • #12329 8309c61 Thanks @florian-lefebvre! - Adds a new astro:routes:resolved hook to the Integration API. Also update the astro:build:done hook by deprecating routes and adding a new assets map.

    When building an integration, you can now get access to routes inside the astro:routes:resolved hook:

    const integration = () => {
      return {
        name: 'my-integration',
        hooks: {
          'astro:routes:resolved': ({ routes }) => {
            console.log(routes);
          },
        },
      };
    };
    

    This hook runs before astro:config:done, and whenever a route changes in development.

    The routes array from astro:build:done is now deprecated, and exposed properties are now available on astro:routes:resolved, except for distURL. For this, you can use the newly exposed assets map:

    const integration = () => {
    +    let routes
        return {
            name: 'my-integration',
            hooks: {
    +            'astro:routes:resolved': (params) => {
    +                routes = params.routes
    +            },
                'astro:build:done': ({
    -                routes
    +                assets
                }) => {
    +                for (const route of routes) {
    +                    const distURL = assets.get(route.pattern)
    +                    if (distURL) {
    +                        Object.assign(route, { distURL })
    +                    }
    +                }
                    console.log(routes)
                }
            }
        }
    }
    
  • #12377 af867f3 Thanks @ascorbic! - Adds experimental support for automatic responsive images

    This feature is experimental and may change in future versions. To enable it, set experimental.responsiveImages to true in your astro.config.mjs file.

    {
       experimental: {
          responsiveImages: true,
       },
    }
    

    When this flag is enabled, you can pass a layout prop to any <Image /> or <Picture /> component to create a responsive image. When a layout is set, images have automatically generated srcset and sizes attributes based on the image's dimensions and the layout type. Images with responsive and full-width layouts will have styles applied to ensure they resize according to their container.

    ---
    import { Image, Picture } from 'astro:assets';
    import myImage from '../assets/my_image.png';
    ---
    
    <Image
      src={myImage}
      alt="A description of my image."
      layout="responsive"
      width={800}
      height={600}
    />
    <Picture
      src={myImage}
      alt="A description of my image."
      layout="full-width"
      formats={['avif', 'webp', 'jpeg']}
    />
    

    This <Image /> component will generate the following HTML output:

    <img
      src="/_astro/my_image.hash3.webp"
      srcset="
        /_astro/my_image.hash1.webp  640w,
        /_astro/my_image.hash2.webp  750w,
        /_astro/my_image.hash3.webp  800w,
        /_astro/my_image.hash4.webp  828w,
        /_astro/my_image.hash5.webp 1080w,
        /_astro/my_image.hash6.webp 1280w,
        /_astro/my_image.hash7.webp 1600w
      "
      alt="A description of my image"
      sizes="(min-width: 800px) 800px, 100vw"
      loading="lazy"
      decoding="async"
      fetchpriority="auto"
      width="800"
      height="600"
      style="--w: 800; --h: 600; --fit: cover; --pos: center;"
      data-astro-image="responsive"
    />
    

    Responsive image properties

    These are additional properties available to the <Image /> and <Picture /> components when responsive images are enabled:

    • layout: The layout type for the image. Can be responsive, fixed, full-width or none. Defaults to value of image.experimentalLayout.
    • fit: Defines how the image should be cropped if the aspect ratio is changed. Values match those of CSS object-fit. Defaults to cover, or the value of image.experimentalObjectFit if set.
    • position: Defines the position of the image crop if the aspect ratio is changed. Values match those of CSS object-position. Defaults to center, or the value of image.experimentalObjectPosition if set.
    • priority: If set, eagerly loads the image. Otherwise images will be lazy-loaded. Use this for your largest above-the-fold image. Defaults to false.

    Default responsive image settings

    You can enable responsive images for all <Image /> and <Picture /> components by setting image.experimentalLayout with a default value. This can be overridden by the layout prop on each component.

    Example:

    {
        image: {
          // Used for all `<Image />` and `<Picture />` components unless overridden
          experimentalLayout: 'responsive',
        },
        experimental: {
          responsiveImages: true,
        },
    }
    
    ---
    import { Image } from 'astro:assets';
    import myImage from '../assets/my_image.png';
    ---
    
    <Image src={myImage} alt="This will use responsive layout" width={800} height={600} />
    
    <Image src={myImage} alt="This will use full-width layout" layout="full-width" />
    
    <Image src={myImage} alt="This will disable responsive images" layout="none" />
    

    For a complete overview, and to give feedback on this experimental API, see the Responsive Images RFC.

  • #12475 3f02d5f Thanks @ascorbic! - Changes the default content config location from src/content/config.* to src/content.config.*.

    The previous location is still supported, and is required if the legacy.collections flag is enabled.

Patch Changes

  • #12424 4364bff Thanks @ematipico! - Fixes an issue where an incorrect usage of Astro actions was lost when porting the fix from v4 to v5

  • #12438 c8f877c Thanks @ascorbic! - Fixes a bug where legacy content types were generated for content layer collections if they were in the content directory

5.0.0-beta.8

Minor Changes

  • #12373 d10f918 Thanks @bholmesdev! - Changes the default behavior for Astro Action form requests to a standard POST submission.

    In Astro 4.x, actions called from an HTML form would trigger a redirect with the result forwarded using cookies. This caused issues for large form errors and return values that exceeded the 4 KB limit of cookie-based storage.

    Astro 5.0 now renders the result of an action as a POST result without any forwarding. This will introduce a "confirm form resubmission?" dialog when a user attempts to refresh the page, though it no longer imposes a 4 KB limit on action return value.

    Customize form submission behavior

    If you prefer to address the "confirm form resubmission?" dialog on refresh, or to preserve action results across sessions, you can now customize action result handling from middleware.

    We recommend using a session storage provider as described in our Netlify Blob example. However, if you prefer the cookie forwarding behavior from 4.X and accept the 4 KB size limit, you can implement the pattern as shown in this sample snippet:

    // src/middleware.ts
    import { defineMiddleware } from 'astro:middleware';
    import { getActionContext } from 'astro:actions';
    
    export const onRequest = defineMiddleware(async (context, next) => {
      // Skip requests for prerendered pages
      if (context.isPrerendered) return next();
    
      const { action, setActionResult, serializeActionResult } = getActionContext(context);
    
      // If an action result was forwarded as a cookie, set the result
      // to be accessible from `Astro.getActionResult()`
      const payload = context.cookies.get('ACTION_PAYLOAD');
      if (payload) {
        const { actionName, actionResult } = payload.json();
        setActionResult(actionName, actionResult);
        context.cookies.delete('ACTION_PAYLOAD');
        return next();
      }
    
      // If an action was called from an HTML form action,
      // call the action handler and redirect with the result as a cookie.
      if (action?.calledFrom === 'form') {
        const actionResult = await action.handler();
    
        context.cookies.set('ACTION_PAYLOAD', {
          actionName: action.name,
          actionResult: serializeActionResult(actionResult),
        });
    
        if (actionResult.error) {
          // Redirect back to the previous page on error
          const referer = context.request.headers.get('Referer');
          if (!referer) {
            throw new Error('Internal: Referer unexpectedly missing from Action POST request.');
          }
          return context.redirect(referer);
        }
        // Redirect to the destination page on success
        return context.redirect(context.originPathname);
      }
    
      return next();
    });
    

Patch Changes

  • #12339 bdb75a8 Thanks @ematipico! - Adds an error when Astro.rewrite() is used to rewrite an on-demand route with a static route when using the "server" output.

    This is a forbidden rewrite because Astro can't retrieve the emitted static route at runtime. This route is served by the hosting platform, and not Astro itself.

5.0.0-beta.7

Minor Changes

5.0.0-beta.6

Major Changes

  • #12268 4e9a3ac Thanks @ematipico! - The command astro add vercel now updates the configuration file differently, and adds @astrojs/vercel as module to import.

    This is a breaking change because it requires the version 8.* of @astrojs/vercel.

  • #12231 90ae100 Thanks @bluwy! - Updates the automatic charset=utf-8 behavior for Markdown pages, where instead of responding with charset=utf-8 in the Content-Type header, Astro will now automatically add the <meta charset="utf-8"> tag instead.

    This behaviour only applies to Markdown pages (.md or similar Markdown files located within src/pages/) that do not use Astro's special layout frontmatter property. It matches the rendering behaviour of other non-content pages, and retains the minimal boilerplate needed to write with non-ASCII characters when adding individual Markdown pages to your site.

    If your Markdown pages use the layout frontmatter property, then HTML encoding will be handled by the designated layout component instead, and the <meta charset="utf-8"> tag will not be added to your page by default.

    If you require charset=utf-8 to render your page correctly, make sure that your layout components contain the <meta charset="utf-8"> tag. You may need to add this if you have not already done so.

Minor Changes

  • #12243 eb41d13 Thanks @florian-lefebvre! - Improves defineConfig type safety. TypeScript will now error if a group of related configuration options do not have consistent types. For example, you will now see an error if your language set for i18n.defaultLocale is not one of the supported locales specified in i18n.locales.

  • #12150 93351bc Thanks @bluwy! - Adds support for passing values other than "production" or "development" to the --mode flag (e.g. "staging", "testing", or any custom value) to change the value of import.meta.env.MODE or the loaded .env file. This allows you take advantage of Vite's mode feature.

    Also adds a new --devOutput flag for astro build that will output a development-based build.

    Note that changing the mode does not change the kind of code transform handled by Vite and Astro:

    • In astro dev, Astro will transform code with debug information.
    • In astro build, Astro will transform code with the most optimized output and removes debug information.
    • In astro build --devOutput (new flag), Astro will transform code with debug information like in astro dev.

    This enables various usecases like:

    # Run the dev server connected to a "staging" API
    astro dev --mode staging
    
    # Build a site that connects to a "staging" API
    astro build --mode staging
    
    # Build a site that connects to a "production" API with additional debug information
    astro build --devOutput
    
    # Build a site that connects to a "testing" API
    astro build --mode testing
    

    The different modes can be used to load different .env files, e.g. .env.staging or .env.production, which can be customized for each environment, for example with different API_URL environment variable values.

Patch Changes

  • #12302 7196c24 Thanks @ematipico! - Fixes an issue where the origin check middleware run for prendered pages

  • #12341 c1786d6 Thanks @ematipico! - Fixes and issue where Astro.currentLocale always returned the default locale when consumed inside a server island.

  • #12270 25192a0 Thanks @ematipico! - Fixes a bug where the params weren't correctly computed when rendering URLs with non-English characters

5.0.0-beta.5

Minor Changes

  • #12226 51d13e2 Thanks @ematipico! - The following renderer fields and integration fields now accept URL as a type:

    Renderers:

    • AstroRenderer.clientEntrpoint
    • AstroRenderer.serverEntrypoint

    Integrations:

    • InjectedRoute.entrypoint
    • AstroIntegrationMiddleware.entrypoint
    • DevToolbarAppEntry.entrypoint

Patch Changes

  • #12168 1cd3085 Thanks @ascorbic! - Allows "slug" as a field in content layer data

  • #12169 15fa9ba Thanks @ematipico! - Fixes a bug where configured redirects were incorrectly constructed when reading the file system.

    This caused an issue where configuring a redirect in astro.config.mjs like { /old: /new }, failed to trigger the correct redirect in the dev server.

  • #12169 15fa9ba Thanks @ematipico! - Fixes a bug where the dev server was not providing a consistent user experience for configured redirects.

    With the fix, when you configure a redirect in astro.config.mjs like this { /old: "/new" }, the dev server return an HTML response that matches the one emitted by a static build.

5.0.0-beta.4

Major Changes

  • #11979 423dfc1 Thanks @bluwy! - Bumps vite dependency to v6.0.0-beta.2. The version is pinned and will be updated as new Vite versions publish to prevent unhandled breaking changes. For the full list of Vite-specific changes, see its changelog.

  • #12100 abf9a89 Thanks @astrobot-houston! - Refactors legacy content and data collections to use the Content Layer API glob() loader for better performance and to support backwards compatibility. Also introduces the legacy.collections flag for projects that are unable to update to the new behavior immediately.

    ⚠️ BREAKING CHANGE FOR LEGACY CONTENT COLLECTIONS ⚠️

    By default, collections that use the old types (content or data) and do not define a loader are now implemented under the hood using the Content Layer API's built-in glob() loader, with extra backward-compatibility handling.

    In order to achieve backwards compatibility with existing content collections, the following have been implemented:

    • a glob loader collection is defined, with patterns that match the previous handling (matches src/content/<collection name>/**/*.md and other content extensions depending on installed integrations, with underscore-prefixed files and folders ignored)
    • When used in the runtime, the entries have an ID based on the filename in the same format as legacy collections
    • A slug field is added with the same format as before
    • A render() method is added to the entry, so they can be called using entry.render()
    • getEntryBySlug is supported

    In order to achieve backwards compatibility with existing data collections, the following have been implemented:

    • a glob loader collection is defined, with patterns that match the previous handling (matches src/content/<collection name>/**/*{.json,.yaml} and other data extensions, with underscore-prefixed files and folders ignored)
    • Entries have an ID that is not slugified
    • getDataEntryById is supported

    While this backwards compatibility implementation is able to emulate most of the features of legacy collections, there are some differences and limitations that may cause breaking changes to existing collections:

    • In previous versions of Astro, collections would be generated for all folders in src/content/, even if they were not defined in src/content/config.ts. This behavior is now deprecated, and collections should always be defined in src/content/config.ts. For existing collections, these can just be empty declarations (e.g. const blog = defineCollection({})) and Astro will implicitly define your legacy collection for you in a way that is compatible with the new loading behavior.
    • The special layout field is not supported in Markdown collection entries. This property is intended only for standalone page files located in src/pages/ and not likely to be in your collection entries. However, if you were using this property, you must now create dynamic routes that include your page styling.
    • Sort order of generated collections is non-deterministic and platform-dependent. This means that if you are calling getCollection(), the order in which entries are returned may be different than before. If you need a specific order, you should sort the collection entries yourself.
    • image().refine() is not supported. If you need to validate the properties of an image you will need to do this at runtime in your page or component.
    • the key argument of getEntry(collection, key) is typed as string, rather than having types for every entry.

    A new legacy configuration flag legacy.collections is added for users that want to keep their current legacy (content and data) collections behavior (available in Astro v2 - v4), or who are not yet ready to update their projects:

    // astro.config.mjs
    import { defineConfig } from 'astro/config';
    
    export default defineConfig({
      legacy: {
        collections: true,
      },
    });
    

    When set, no changes to your existing collections are necessary, and the restrictions on storing both new and old collections continue to exist: legacy collections (only) must continue to remain in src/content/, while new collections using a loader from the Content Layer API are forbidden in that folder.

  • #12079 7febf1f Thanks @ematipico! - params passed in getStaticPaths are no longer automatically decoded.

    [changed]: params aren't decoded anymore.

    In Astro v4.x, params in were automatically decoded using decodeURIComponent.

    Astro v5.0 doesn't automatically decode params in getStaticPaths anymore, so you'll need to manually decode them yourself if needed

    What should I do?

    If you were relying on the automatic decode, you'll need to manually decode it using decodeURI.

    Note that the use of decodeURIComponent) is discouraged for getStaticPaths because it decodes more characters than it should, for example /, ?, # and more.

    ---
    export function getStaticPaths() {
      return [
    +    { params: { id: decodeURI("%5Bpage%5D") } },
    -    { params: { id: "%5Bpage%5D" } },
      ]
    }
    
    const { id } = Astro.params;
    ---
    

Patch Changes

5.0.0-beta.3

Minor Changes

  • #12047 21b5e80 Thanks @rgodha24! - Adds a new optional parser property to the built-in file() loader for content collections to support additional file types such as toml and csv.

    The file() loader now accepts a second argument that defines a parser function. This allows you to specify a custom parser (e.g. toml.parse or csv-parse) to create a collection from a file's contents. The file() loader will automatically detect and parse JSON and YAML files (based on their file extension) with no need for a parser.

    This works with any type of custom file formats including csv and toml. The following example defines a content collection dogs using a .toml file.

    [[dogs]]
    id = "..."
    age = "..."
    
    [[dogs]]
    id = "..."
    age = "..."
    

    After importing TOML's parser, you can load the dogs collection into your project by passing both a file path and parser to the file() loader.

    import { defineCollection } from "astro:content"
    import { file } from "astro/loaders"
    import { parse as parseToml } from "toml"
    
    const dogs = defineCollection({
      loader: file("src/data/dogs.toml", { parser: (text) => parseToml(text).dogs }),
      schema: /* ... */
    })
    
    // it also works with CSVs!
    import { parse as parseCsv } from "csv-parse/sync";
    
    const cats = defineCollection({
      loader: file("src/data/cats.csv", { parser: (text) => parseCsv(text, { columns: true, skipEmptyLines: true })})
    });
    

    The parser argument also allows you to load a single collection from a nested JSON document. For example, this JSON file contains multiple collections:

    { "dogs": [{}], "cats": [{}] }
    

    You can separate these collections by passing a custom parser to the file() loader like so:

    const dogs = defineCollection({
      loader: file('src/data/pets.json', { parser: (text) => JSON.parse(text).dogs }),
    });
    const cats = defineCollection({
      loader: file('src/data/pets.json', { parser: (text) => JSON.parse(text).cats }),
    });
    

    And it continues to work with maps of id to data

    bubbles:
      breed: 'Goldfish'
      age: 2
    finn:
      breed: 'Betta'
      age: 1
    
    const fish = defineCollection({
      loader: file('src/data/fish.yaml'),
      schema: z.object({ breed: z.string(), age: z.number() }),
    });
    
  • #12071 61d248e Thanks @Princesseuh! - astro add no longer automatically sets output: 'server'. Since the default value of output now allows for server-rendered pages, it no longer makes sense to default to full server builds when you add an adapter

  • #11963 0a1036e Thanks @florian-lefebvre! - Adds a new createCodegenDir() function to the astro:config:setup hook in the Integrations API

    In 4.14, we introduced the injectTypes utility on the astro:config:done hook. It can create .d.ts files and make their types available to user's projects automatically. Under the hood, it creates a file in <root>/.astro/integrations/<normalized_integration_name>.

    While the .astro directory has always been the preferred place to write code generated files, it has also been prone to mistakes. For example, you can write a .astro/types.d.ts file, breaking Astro types. Or you can create a file that overrides a file created by another integration.

    In this release, <root>/.astro/integrations/<normalized_integration_name> can now be retrieved in the astro:config:setup hook by calling createCodegenDir(). It allows you to have a dedicated folder, avoiding conflicts with another integration or Astro itself. This directory is created by calling this function so it's safe to write files to it directly:

    import { writeFileSync } from 'node:fs';
    
    const integration = {
      name: 'my-integration',
      hooks: {
        'astro:config:setup': ({ createCodegenDir }) => {
          const codegenDir = createCodegenDir();
          writeFileSync(new URL('cache.json', codegenDir), '{}', 'utf-8');
        },
      },
    };
    
  • #12081 8679954 Thanks @florian-lefebvre! - Removes the experimental contentCollectionsCache introduced in 3.5.0.

    Astro Content Layer API independently solves some of the caching and performance issues with legacy content collections that this strategy attempted to address. This feature has been replaced with continued work on improvements to the content layer. If you were using this experimental feature, you must now remove the flag from your Astro config as it no longer exists:

    export default defineConfig({
        experimental: {
    -        contentCollectionsCache: true
        }
    })
    

    The cacheManifest boolean argument is no longer passed to the astro:build:done integration hook:

    const integration = {
        name: "my-integration",
        hooks: {
            "astro:build:done": ({
    -            cacheManifest,
                logger
            }) => {}
        }
    }
    

Patch Changes

  • #12073 acf264d Thanks @bluwy! - Replaces ora with yocto-spinner

  • #12075 a19530e Thanks @bluwy! - Parses frontmatter ourselves

  • #12070 9693ad4 Thanks @ematipico! - Fixes an issue where the check origin middleware was incorrectly injected when the build output was "static"

  • Updated dependencies [a19530e]:

    • @astrojs/markdown-remark@6.0.0-beta.2

5.0.0-beta.2

Patch Changes

  • #12035 325a57c Thanks @ascorbic! - Correctly parse values returned from inline loader

  • #12022 ddc3a08 Thanks @Princesseuh! - Properly handle including trailing slash on the image endpoint route based on the trailingSlash config

  • #12016 837ee3a Thanks @matthewp! - Fixes actions with large amount of validation errors

  • #12030 10a756a Thanks @ascorbic! - Resolves image paths in content layer with initial slash as project-relative

    When using the image() schema helper, previously paths with an initial slash were treated as public URLs. This was to match the behavior of markdown images. However this is a change from before, where paths with an initial slash were treated as project-relative. This change restores the previous behavior, so that paths with an initial slash are treated as project-relative.

5.0.0-beta.1

Major Changes

  • #12008 5608338 Thanks @Princesseuh! - Welcome to the Astro 5 beta! This release has no changes from the latest alpha of this package, but it does bring us one step closer to the final, stable release.

    Starting from this release, no breaking changes will be introduced unless absolutely necessary.

    To learn how to upgrade, check out the Astro v5.0 upgrade guide in our beta docs site.

Patch Changes

  • Updated dependencies [5608338]:
    • @astrojs/markdown-remark@6.0.0-beta.1

5.0.0-alpha.9

Patch Changes

5.0.0-alpha.8

Major Changes

  • #11982 d84e444 Thanks @Princesseuh! - Adds a default exclude and include value to the tsconfig presets. {projectDir}/dist is now excluded by default, and {projectDir}/.astro/types.d.ts and {projectDir}/**/* are included by default.

    Both of these options can be overridden by setting your own values to the corresponding settings in your tsconfig.json file.

  • #11987 bf90a53 Thanks @florian-lefebvre! - The locals object can no longer be overridden

    Middleware, API endpoints, and pages can no longer override the locals object in its entirety. You can still append values onto the object, but you can not replace the entire object and delete its existing values.

    If you were previously overwriting like so:

    ctx.locals = {
      one: 1,
      two: 2,
    };
    

    This can be changed to an assignment on the existing object instead:

    Object.assign(ctx.locals, {
      one: 1,
      two: 2,
    });
    

Minor Changes

  • #11980 a604a0c Thanks @matthewp! - ViewTransitions component renamed to ClientRouter

    The <ViewTransitions /> component has been renamed to <ClientRouter />. There are no other changes than the name. The old name will continue to work in Astro 5.x, but will be removed in 6.0.

    This change was done to clarify the role of the component within Astro's View Transitions support. Astro supports View Transitions APIs in a few different ways, and renaming the component makes it more clear that the features you get from the ClientRouter component are slightly different from what you get using the native CSS-based MPA router.

    We still intend to maintain the ClientRouter as before, and it's still important for use-cases that the native support doesn't cover, such as persisting state between pages.

Patch Changes

  • #11987 bf90a53 Thanks @florian-lefebvre! - render() signature now takes renderOptions as 2nd argument

    The signature for app.render() has changed, and the second argument is now an options object called renderOptions with more options for customizing rendering.

    The renderOptions are:

    • addCookieHeader: Determines whether Astro will set the Set-Cookie header, otherwise the adapter is expected to do so itself.
    • clientAddress: The client IP address used to set Astro.clientAddress.
    • locals: An object of locals that's set to Astro.locals.
    • routeData: An object specifying the route to use.
  • #11991 d7a396c Thanks @matthewp! - Update error link to on-demand rendering guide

5.0.0-alpha.7

Major Changes

  • #11864 ee38b3a Thanks @ematipico! - ### [changed]: entryPoint type inside the hook astro:build:ssr In Astro v4.x, the entryPoint type was RouteData.

    Astro v5.0 the entryPoint type is IntegrationRouteData, which contains a subset of the RouteData type. The fields isIndex and fallbackRoutes were removed.

    What should I do?

    Update your adapter to change the type of entryPoint from RouteData to IntegrationRouteData.

    -import type {RouteData} from 'astro';
    +import type {IntegrationRouteData} from "astro"
    
    -function useRoute(route: RouteData) {
    +function useRoute(route: IntegrationRouteData) {
    
    }
    
  • #11908 518433e Thanks @Princesseuh! - The image.endpoint config now allow customizing the route of the image endpoint in addition to the entrypoint. This can be useful in niche situations where the default route /_image conflicts with an existing route or your local server setup.

    import { defineConfig } from 'astro/config';
    
    defineConfig({
      image: {
        endpoint: {
          route: '/image',
          entrypoint: './src/image_endpoint.ts',
        },
      },
    });
    
  • #11806 f7f2338 Thanks @Princesseuh! - Removes the assets property on supportedAstroFeatures for adapters, as it did not reflect reality properly in many cases.

    Now, relating to assets, only a single sharpImageService property is available, determining if the adapter is compatible with the built-in sharp image service.

  • #11864 ee38b3a Thanks @ematipico! - ### [changed]: routes type inside the hook astro:build:done In Astro v4.x, the routes type was RouteData.

    Astro v5.0 the routes type is IntegrationRouteData, which contains a subset of the RouteData type. The fields isIndex and fallbackRoutes were removed.

    What should I do?

    Update your adapter to change the type of routes from RouteData to IntegrationRouteData.

    -import type {RouteData} from 'astro';
    +import type {IntegrationRouteData} from "astro"
    
    -function useRoute(route: RouteData) {
    +function useRoute(route: IntegrationRouteData) {
    
    }
    
  • #11864 ee38b3a Thanks @ematipico! - ### [changed]: RouteData.distURL is now an array In Astro v4.x, RouteData.distURL was undefined or a URL

    Astro v5.0, RouteData.distURL is undefined or an array of URL. This was a bug, because a route can generate multiple files on disk, especially when using dynamic routes such as [slug] or [...slug].

    What should I do?

    Update your code to handle RouteData.distURL as an array.

    if (route.distURL) {
    -  if (route.distURL.endsWith('index.html')) {
    -    // do something
    -  }
    +  for (const url of route.distURL) {
    +    if (url.endsWith('index.html')) {
    +      // do something
    +    }
    +  }
    }
    

Minor Changes

  • #11806 f7f2338 Thanks @Princesseuh! - The value of the different properties on supportedAstroFeatures for adapters can now be objects, with a support and message properties. The content of the message property will be shown in the Astro CLI when the adapter is not compatible with the feature, allowing one to give a better informational message to the user.

    This is notably useful with the new limited value, to explain to the user why support is limited.

  • #11955 d813262 Thanks @matthewp! - Server Islands introduced behind an experimental flag in v4.12.0 is no longer experimental and is available for general use.

    Server islands are Astro's solution for highly cacheable pages of mixed static and dynamic content. They allow you to specify components that should run on the server, allowing the rest of the page to be more aggressively cached, or even generated statically.

    Turn any .astro component into a server island by adding the server:defer directive and optionally, fallback placeholder content. It will be rendered dynamically at runtime outside the context of the rest of the page, allowing you to add longer cache headers for the pages, or even prerender them.

    ---
    import Avatar from '../components/Avatar.astro';
    import GenericUser from '../components/GenericUser.astro';
    ---
    
    <header>
      <h1>Page Title</h1>
      <div class="header-right">
        <Avatar server:defer>
          <GenericUser slot="fallback" />
        </Avatar>
      </div>
    </header>
    

    If you were previously using this feature, please remove the experimental flag from your Astro config:

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

    If you have been waiting for stabilization before using server islands, you can now do so.

    Please see the server island documentation for more about this feature.

  • #11806 f7f2338 Thanks @Princesseuh! - Adds a new limited value for the different properties of supportedAstroFeatures for adapters, which indicates that the adapter is compatible with the feature, but with some limitations. This is useful for adapters that support a feature, but not in all cases or with all options.

  • #11925 74722cb Thanks @florian-lefebvre! - Updates astro/config import to reference astro/client types

    When importing astro/config, types from astro/client will be made automatically available to your project. If your project tsconfig.json changes how references behave, you'll still have access to these types after running astro sync.

Patch Changes

5.0.0-alpha.6

Major Changes

  • #11941 b6a5f39 Thanks @Princesseuh! - Merges the output: 'hybrid' and output: 'static' configurations into one single configuration (now called 'static') that works the same way as the previous hybrid option.

    It is no longer necessary to specify output: 'hybrid' in your Astro config to use server-rendered pages. The new output: 'static' has this capability included. Astro will now automatically provide the ability to opt out of prerendering in your static site with no change to your output configuration required. Any page route or endpoint can include export const prerender = false to be server-rendered, while the rest of your site is statically-generated.

    If your project used hybrid rendering, you must now remove the output: 'hybrid' option from your Astro config as it no longer exists. However, no other changes to your project are required, and you should have no breaking changes. The previous 'hybrid' behavior is now the default, under a new name 'static'.

    If you were using the output: 'static' (default) option, you can continue to use it as before. By default, all of your pages will continue to be prerendered and you will have a completely static site. You should have no breaking changes to your project.

    import { defineConfig } from "astro/config";
    
    export default defineConfig({
    -  output: 'hybrid',
    });
    

    An adapter is still required to deploy an Astro project with any server-rendered pages. Failure to include an adapter will result in a warning in development and an error at build time.

Minor Changes

  • #11941 b6a5f39 Thanks @Princesseuh! - Adapters can now specify the build output type they're intended for using the adapterFeatures.buildOutput property. This property can be used to always generate a server output, even if the project doesn't have any server-rendered pages.

    {
      'astro:config:done': ({ setAdapter, config }) => {
        setAdapter({
          name: 'my-adapter',
          adapterFeatures: {
            buildOutput: 'server',
          },
        });
      },
    }
    

    If your adapter specifies buildOutput: 'static', and the user's project contains server-rendered pages, Astro will warn in development and error at build time. Note that a hybrid output, containing both static and server-rendered pages, is considered to be a server output, as a server is required to serve the server-rendered pages.

  • #11941 b6a5f39 Thanks @Princesseuh! - Adds a new buildOutput property to the astro:config:done hook returning the build output type.

    This can be used to know if the user's project will be built as a static site (HTML files), or a server-rendered site (whose exact output depends on the adapter).

Patch Changes

  • #11960 4410130 Thanks @ascorbic! - Fixes an issue where the refresh context data was not passed correctly to content layer loaders

  • #11952 50a0146 Thanks @ascorbic! - Adds support for array patterns in the built-in glob() content collections loader

    The glob loader can now accept an array of multiple patterns as well as string patterns. This allows you to more easily combine multiple patterns into a single collection, and also means you can use negative matches to exclude files from the collection.

    const probes = defineCollection({
      // Load all markdown files in the space-probes directory, except for those that start with "voyager-"
      loader: glob({ pattern: ['*.md', '!voyager-*'], base: 'src/data/space-probes' }),
      schema: z.object({
        name: z.string(),
        type: z.enum(['Space Probe', 'Mars Rover', 'Comet Lander']),
        launch_date: z.date(),
        status: z.enum(['Active', 'Inactive', 'Decommissioned']),
        destination: z.string(),
        operator: z.string(),
        notable_discoveries: z.array(z.string()),
      }),
    });
    
  • #11968 86ad1fd Thanks @NikolaRHristov! - Fixes a typo in the server island JSDoc

  • #11983 633eeaa Thanks @uwej711! - Remove dependency on path-to-regexp

5.0.0-alpha.5

Major Changes

  • #11916 46ea29f Thanks @bluwy! - Updates how the build.client and build.server option values get resolved to match existing documentation. With this fix, the option values will now correctly resolve relative to the outDir option. So if outDir is set to ./dist/nested/, then by default:

    • build.client will resolve to <root>/dist/nested/client/
    • build.server will resolve to <root>/dist/nested/server/

    Previously the values were incorrectly resolved:

    • build.client was resolved to <root>/dist/nested/dist/client/
    • build.server was resolved to <root>/dist/nested/dist/server/

    If you were relying on the previous build paths, make sure that your project code is updated to the new build paths.

Minor Changes

  • #11875 a8a3d2c Thanks @florian-lefebvre! - Adds a new property isPrerendered to the globals Astro and APIContext . This boolean value represents whether or not the current page is prerendered:

    ---
    // src/pages/index.astro
    
    export const prerender = true;
    ---
    
    // src/middleware.js
    
    export const onRequest = (ctx, next) => {
      console.log(ctx.isPrerendered); // it will log true
      return next();
    };
    

Patch Changes

  • #11927 5b4e3ab Thanks @florian-lefebvre! - Updates the env configuration reference docs to include a full API reference for envField.

  • #11943 fa4671c Thanks @sarah11918! - Updates error messages that assume content collections are located in src/content/ with more generic language

5.0.0-alpha.4

Major Changes

  • #11859 3804711 Thanks @florian-lefebvre! - Changes the default tsconfig.json with better defaults, and makes src/env.d.ts optional

    Astro's default tsconfig.json in starter examples has been updated to include generated types and exclude your build output. This means that src/env.d.ts is only necessary if you have added custom type declarations or if you're not using a tsconfig.json file.

    Additionally, running astro sync no longer creates, nor updates, src/env.d.ts as it is not required for type-checking standard Astro projects.

    To update your project to Astro's recommended TypeScript settings, please add the following include and exclude properties to tsconfig.json:

    {
        "extends": "astro/tsconfigs/base",
    +    "include": [".astro/types.d.ts", "**/*"],
    +    "exclude": ["dist"]
    }
    

Minor Changes

  • #11911 c3dce83 Thanks @ascorbic! - The Content Layer API introduced behind a flag in 4.14.0 is now stable and ready for use in Astro v5.0.

    The new Content Layer API builds upon content collections, taking them beyond local files in src/content/ and allowing you to fetch content from anywhere, including remote APIs. These new collections work alongside your existing content collections, and you can migrate them to the new API at your own pace. There are significant improvements to performance with large collections of local files. For more details, see the Content Layer RFC.

    If you previously used this feature, you can now remove the experimental.contentLayer flag from your Astro config:

    // astro.config.mjs
    import { defineConfig } from 'astro'
    
    export default defineConfig({
    -  experimental: {
    -    contentLayer: true
    -  }
    })
    

    Loading your content

    The core of the new Content Layer API is the loader, a function that fetches content from a source and caches it in a local data store. Astro 4.14 ships with built-in glob() and file() loaders to handle your local Markdown, MDX, Markdoc, and JSON files:

    // src/content/config.ts
    import { defineCollection, z } from 'astro:content';
    import { glob } from 'astro/loaders';
    
    const blog = defineCollection({
      // The ID is a slug generated from the path of the file relative to `base`
      loader: glob({ pattern: '**/*.md', base: './src/data/blog' }),
      schema: z.object({
        title: z.string(),
        description: z.string(),
        publishDate: z.coerce.date(),
      }),
    });
    
    export const collections = { blog };
    

    You can then query using the existing content collections functions, and use a simplified render() function to display your content:

    ---
    import { getEntry, render } from 'astro:content';
    
    const post = await getEntry('blog', Astro.params.slug);
    
    const { Content } = await render(entry);
    ---
    
    <Content />
    

    Creating a loader

    You're not restricted to the built-in loaders we hope you'll try building your own. You can fetch content from anywhere and return an array of entries:

    // src/content/config.ts
    const countries = defineCollection({
      loader: async () => {
        const response = await fetch('https://restcountries.com/v3.1/all');
        const data = await response.json();
        // Must return an array of entries with an id property,
        // or an object with IDs as keys and entries as values
        return data.map((country) => ({
          id: country.cca3,
          ...country,
        }));
      },
      // optionally add a schema to validate the data and make it type-safe for users
      // schema: z.object...
    });
    
    export const collections = { countries };
    

    For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading, and gives full access to the data store. It also allows a loader to define its own schema, including generating it dynamically based on the source API. See the the Content Layer API RFC for more details.

    Sharing your loaders

    Loaders are better when they're shared. You can create a package that exports a loader and publish it to npm, and then anyone can use it on their site. We're excited to see what the community comes up with! To get started, take a look at some examples. Here's how to load content using an RSS/Atom feed loader:

    // src/content/config.ts
    import { defineCollection } from 'astro:content';
    import { feedLoader } from '@ascorbic/feed-loader';
    
    const podcasts = defineCollection({
      loader: feedLoader({
        url: 'https://feeds.99percentinvisible.org/99percentinvisible',
      }),
    });
    
    export const collections = { podcasts };
    

    To learn more, see the Content Layer RFC.

Patch Changes

  • #11902 d63bc50 Thanks @ascorbic! - Fixes case where content layer did not update during clean dev builds on Linux and Windows

  • #11914 b5d827b Thanks @ascorbic! - Exports types for all LoaderContext properties from astro/loaders to make it easier to use them in custom loaders. The ScopedDataStore interface (which was previously internal) is renamed to DataStore, to reflect the fact that it's the only public API for the data store.

5.0.0-alpha.3

Major Changes

  • #11861 3ab3b4e Thanks @bluwy! - Cleans up Astro-specific metadata attached to vfile.data in Remark and Rehype plugins. Previously, the metadata was attached in different locations with inconsistent names. The metadata is now renamed as below:

    • vfile.data.__astroHeadings -> vfile.data.astro.headings
    • vfile.data.imagePaths -> vfile.data.astro.imagePaths

    The types of imagePaths has also been updated from Set<string> to string[]. The vfile.data.astro.frontmatter metadata is left unchanged.

    While we don't consider these APIs public, they can be accessed by Remark and Rehype plugins that want to re-use Astro's metadata. If you are using these APIs, make sure to access them in the new locations.

  • #11825 560ef15 Thanks @bluwy! - Updates internal Shiki rehype plugin to highlight code blocks as hast (using Shiki's codeToHast() API). This allows a more direct Markdown and MDX processing, and improves the performance when building the project, but may cause issues with existing Shiki transformers.

    If you are using Shiki transformers passed to markdown.shikiConfig.transformers, you must make sure they do not use the postprocess hook as it no longer runs on code blocks in .md and .mdx files. (See the Shiki documentation on transformer hooks for more information).

    Code blocks in .mdoc files and <Code /> component do not use the internal Shiki rehype plugin and are unaffected.

  • #11819 2bdde80 Thanks @bluwy! - Updates the Astro config loading flow to ignore processing locally-linked dependencies with Vite (e.g. npm link, in a monorepo, etc). Instead, they will be normally imported by the Node.js runtime the same way as other dependencies from node_modules.

    Previously, Astro would process locally-linked dependencies which were able to use Vite features like TypeScript when imported by the Astro config file.

    However, this caused confusion as integration authors may test against a package that worked locally, but not when published. This method also restricts using CJS-only dependencies because Vite requires the code to be ESM. Therefore, Astro's behaviour is now changed to ignore processing any type of dependencies by Vite.

    In most cases, make sure your locally-linked dependencies are built to JS before running the Astro project, and the config loading should work as before.

Patch Changes

  • #11878 334948c Thanks @ascorbic! - Adds a new function refreshContent to the astro:server:setup hook that allows integrations to refresh the content layer. This can be used, for example, to register a webhook endpoint during dev, or to open a socket to a CMS to listen for changes.

    By default, refreshContent will refresh all collections. You can optionally pass a loaders property, which is an array of loader names. If provided, only collections that use those loaders will be refreshed. For example, A CMS integration could use this property to only refresh its own collections.

    You can also pass a context object to the loaders. This can be used to pass arbitrary data, such as the webhook body, or an event from the websocket.

     {
        name: 'my-integration',
        hooks: {
            'astro:server:setup': async ({ server, refreshContent }) => {
                server.middlewares.use('/_refresh', async (req, res) => {
                    if(req.method !== 'POST') {
                      res.statusCode = 405
                      res.end('Method Not Allowed');
                      return
                    }
                    let body = '';
                    req.on('data', chunk => {
                        body += chunk.toString();
                    });
                    req.on('end', async () => {
                        try {
                            const webhookBody = JSON.parse(body);
                            await refreshContent({
                              context: { webhookBody },
                              loaders: ['my-loader']
                            });
                            res.writeHead(200, { 'Content-Type': 'application/json' });
                            res.end(JSON.stringify({ message: 'Content refreshed successfully' }));
                        } catch (error) {
                            res.writeHead(500, { 'Content-Type': 'application/json' });
                            res.end(JSON.stringify({ error: 'Failed to refresh content: ' + error.message }));
                        }
                    });
                });
            }
        }
    }
    
  • Updated dependencies [3ab3b4e, 560ef15, 3ab3b4e]:

    • @astrojs/markdown-remark@6.0.0-alpha.1

5.0.0-alpha.2

Major Changes

  • #11826 7315050 Thanks @matthewp! - Deprecate Astro.glob

    The Astro.glob function has been deprecated in favor of Content Collections and import.meta.glob.

    Also consider using glob packages from npm, like fast-glob, especially if statically generating your site, as it is faster for most use-cases.

    The easiest path is to migrate to import.meta.glob like so:

    - const posts = Astro.glob('./posts/*.md');
    + const posts = Object.values(import.meta.glob('./posts/*.md', { eager: true }));
    
  • #11827 a83e362 Thanks @matthewp! - Prevent usage of astro:content in the client

    Usage of astro:content in the client has always been discouraged because it leads to all of your content winding up in your client bundle, and can possibly leaks secrets.

    This formally makes doing so impossible, adding to the previous warning with errors.

    In the future Astro might add APIs for client-usage based on needs.

  • #11253 4e5cc5a Thanks @kevinzunigacuellar! - Changes the data returned for page.url.current, page.url.next, page.url.prev, page.url.first and page.url.last to include the value set for base in your Astro config.

    Previously, you had to manually prepend your configured value for base to the URL path. Now, Astro automatically includes your base value in next and prev URLs.

    If you are using the paginate() function for "previous" and "next" URLs, remove any existing base value as it is now added for you:

    ---
    export async function getStaticPaths({ paginate }) {
      const astronautPages = [{
        astronaut: 'Neil Armstrong',
      }, {
        astronaut: 'Buzz Aldrin',
      }, {
        astronaut: 'Sally Ride',
      }, {
        astronaut: 'John Glenn',
      }];
      return paginate(astronautPages, { pageSize: 1 });
    }
    const { page } = Astro.props;
    // `base: /'docs'` configured in `astro.config.mjs`
    - const prev = "/docs" + page.url.prev;
    + const prev = page.url.prev;
    ---
    <a id="prev" href={prev}>Back</a>
    

Minor Changes

  • #11698 05139ef Thanks @ematipico! - Adds a new property to the globals Astro and APIContext called routePattern. The routePattern represents the current route (component) that is being rendered by Astro. It's usually a path pattern will look like this: blog/[slug]:

    ---
    // src/pages/blog/[slug].astro
    const route = Astro.routePattern;
    console.log(route); // it will log "blog/[slug]"
    ---
    
    // src/pages/index.js
    
    export const GET = (ctx) => {
      console.log(ctx.routePattern); // it will log src/pages/index.js
      return new Response.json({ loreum: 'ipsum' });
    };
    

Patch Changes

  • #11791 9393243 Thanks @bluwy! - Updates Astro's default <script> rendering strategy and removes the experimental.directRenderScript option as this is now the default behavior: scripts are always rendered directly. This new strategy prevents scripts from being executed in pages where they are not used.

    Scripts will directly render as declared in Astro files (including existing features like TypeScript, importing node_modules, and deduplicating scripts). You can also now conditionally render scripts in your Astro file.

    However, this means scripts are no longer hoisted to the <head>, multiple scripts on a page are no longer bundled together, and the <script> tag may interfere with the CSS styling.

    As this is a potentially breaking change to your script behavior, please review your <script> tags and ensure that they behave as expected.

5.0.0-alpha.1

Major Changes

  • #11798 e9e2139 Thanks @matthewp! - Unflag globalRoutePriority

    The previously experimental feature globalRoutePriority is now the default in Astro 5.

    This was a refactoring of route prioritization in Astro, making it so that injected routes, file-based routes, and redirects are all prioritized using the same logic. This feature has been enabled for all Starlight projects since it was added and should not affect most users.

  • #11679 ea71b90 Thanks @florian-lefebvre! - The astro:env feature introduced behind a flag in v4.10.0 is no longer experimental and is available for general use. If you have been waiting for stabilization before using astro:env, you can now do so.

    This feature lets you configure a type-safe schema for your environment variables, and indicate whether they should be available on the server or the client.

    To configure a schema, add the env option to your Astro config and define your client and server variables. If you were previously using this feature, please remove the experimental flag from your Astro config and move your entire env configuration unchanged to a top-level option.

    import { defineConfig, envField } from 'astro/config';
    
    export default defineConfig({
      env: {
        schema: {
          API_URL: envField.string({ context: 'client', access: 'public', optional: true }),
          PORT: envField.number({ context: 'server', access: 'public', default: 4321 }),
          API_SECRET: envField.string({ context: 'server', access: 'secret' }),
        },
      },
    });
    

    You can import and use your defined variables from the appropriate /client or /server module:

    ---
    import { API_URL } from 'astro:env/client';
    import { API_SECRET_TOKEN } from 'astro:env/server';
    
    const data = await fetch(`${API_URL}/users`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${API_SECRET_TOKEN}`,
      },
    });
    ---
    
    <script>
      import { API_URL } from 'astro:env/client';
    
      fetch(`${API_URL}/ping`);
    </script>
    
  • #11788 7c0ccfc Thanks @ematipico! - Updates the default value of security.checkOrigin to true, which enables Cross-Site Request Forgery (CSRF) protection by default for pages rendered on demand.

    If you had previously configured security.checkOrigin: true, you no longer need this set in your Astro config. This is now the default and it is safe to remove.

    To disable this behavior and opt out of automatically checking that the “origin” header matches the URL sent by each request, you must explicitly set security.checkOrigin: false:

    export default defineConfig({
    +  security: {
    +    checkOrigin: false
    +  }
    })
    
  • #11741 6617491 Thanks @bluwy! - Removes internal JSX handling and moves the responsibility to the @astrojs/mdx package directly. The following exports are also now removed:

    • astro/jsx/babel.js
    • astro/jsx/component.js
    • astro/jsx/index.js
    • astro/jsx/renderer.js
    • astro/jsx/server.js
    • astro/jsx/transform-options.js

    If your project includes .mdx files, you must upgrade @astrojs/mdx to the latest version so that it doesn't rely on these entrypoints to handle your JSX.

  • #11782 9a2aaa0 Thanks @Princesseuh! - Makes the compiledContent property of Markdown content an async function, this change should fix underlying issues where sometimes when using a custom image service and images inside Markdown, Node would exit suddenly without any error message.

    ---
    import * as myPost from "../post.md";
    
    - const content = myPost.compiledContent();
    + const content = await myPost.compiledContent();
    ---
    
    <Fragment set:html={content} />
    
  • #11770 cfa6a47 Thanks @Princesseuh! - Removed support for the Squoosh image service. As the underlying library libsquoosh is no longer maintained, and the image service sees very little usage we have decided to remove it from Astro.

    Our recommendation is to use the base Sharp image service, which is more powerful, faster, and more actively maintained.

    - import { squooshImageService } from "astro/config";
    import { defineConfig } from "astro/config";
    
    export default defineConfig({
    -  image: {
    -    service: squooshImageService()
    -  }
    });
    

    If you are using this service, and cannot migrate to the base Sharp image service, a third-party extraction of the previous service is available here: https://github.com/Princesseuh/astro-image-service-squoosh

5.0.0-alpha.0

Major Changes

  • #10742 b6fbdaa Thanks @ematipico! - The lowest version of Node supported by Astro is now Node v18.17.1 and higher.

  • #11715 d74617c Thanks @Princesseuh! - Refactor the exported types from the astro module. There should normally be no breaking changes, but if you relied on some previously deprecated types, these might now have been fully removed.

    In most cases, updating your code to move away from previously deprecated APIs in previous versions of Astro should be enough to fix any issues.

  • #11660 e90f559 Thanks @bluwy! - Fixes attribute rendering for non-boolean HTML attributes with boolean values to match proper attribute handling in browsers.

    Previously, non-boolean attributes may not have included their values when rendered to HTML. In Astro v5.0, the values are now explicitly rendered as ="true" or ="false"

    In the following .astro examples, only allowfullscreen is a boolean attribute:

    <!-- src/pages/index.astro --><!-- `allowfullscreen` is a boolean attribute -->
    <p allowfullscreen={true}></p>
    <p allowfullscreen={false}></p>
    
    <!-- `inherit` is *not* a boolean attribute -->
    <p inherit={true}></p>
    <p inherit={false}></p>
    
    <!-- `data-*` attributes are not boolean attributes -->
    <p data-light={true}></p>
    <p data-light={false}></p>
    

    Astro v5.0 now preserves the full data attribute with its value when rendering the HTML of non-boolean attributes:

      <p allowfullscreen></p>
      <p></p>
    
      <p inherit="true"></p>
    - <p inherit></p>
    + <p inherit="false"></p>
    
    - <p data-light></p>
    + <p data-light="true"></p>
    - <p></p>
    + <p data-light="false"></p>
    

    If you rely on attribute values, for example to locate elements or to conditionally render, update your code to match the new non-boolean attribute values:

    - el.getAttribute('inherit') === ''
    + el.getAttribute('inherit') === 'false'
    
    - el.hasAttribute('data-light')
    + el.dataset.light === 'true'
    
  • #11714 8a53517 Thanks @matthewp! - Remove support for functionPerRoute

    This change removes support for the functionPerRoute option both in Astro and @astrojs/vercel.

    This option made it so that each route got built as separate entrypoints so that they could be loaded as separate functions. The hope was that by doing this it would decrease the size of each function. However in practice routes use most of the same code, and increases in function size limitations made the potential upsides less important.

    Additionally there are downsides to functionPerRoute, such as hitting limits on the number of functions per project. The feature also never worked with some Astro features like i18n domains and request rewriting.

    Given this, the feature has been removed from Astro.

Patch Changes