Skip to content

feat(session): add session: false to opt out of session support - #16871

Merged
ematipico merged 5 commits into
withastro:mainfrom
adamchal:session-false
Aug 5, 2026
Merged

feat(session): add session: false to opt out of session support#16871
ematipico merged 5 commits into
withastro:mainfrom
adamchal:session-false

Conversation

@adamchal

@adamchal adamchal commented May 26, 2026

Copy link
Copy Markdown
Contributor

Astro unconditionally bundles the session runtime (AstroSession + unstorage) into SSR output whenever the session provider is statically imported, even when no driver is ever wired and Astro.session is always undefined at runtime. For projects that never use sessions, this carries cold-start parse cost (especially on serverless/edge), latent attack surface in cookie/session-storage code paths, and a larger dependency tree. There was no first-class opt-out, and no tree-shaking for the common "no sessions configured" case.

Changes

  • Adds a session: false config option that opts a project out of session support entirely.
  • Tree-shakes the session runtime (AstroSession + unstorage) out of the SSR bundle for any project where no session driver is wired — session: false, no session config at all, or a session object without a driver.
  • Astro.session (and context.session) is undefined whenever no driver is present, matching its existing AstroSession | undefined type. Existing if (Astro.session) feature-detection keeps working; there is no new throwing state to reason about.
  • Adapter changes (@astrojs/cloudflare, @astrojs/netlify, @astrojs/node): skip auto-wiring the default session driver when session: false.
import { defineConfig } from 'astro/config';

export default defineConfig({
  session: false,
});

Projects that already wire a session driver (user-configured or adapter default) see no behavior change — the runtime is retained whenever a driver is configured.

Changed since the first review. The initial version made Astro.session throw a SessionDisabledError under session: false, per earlier RFC guidance. Following review feedback, this now leaves it undefined instead: Astro.session is already typed AstroSession | undefined, so reusing the existing "not available" state keeps the feature-detection contract intact, avoids a third state that user code would have to branch on, and removes a large amount of signal-threading. The tree-shaking was also extended to any driver-less project, so the bundle savings apply automatically wherever sessions are unused.

Testing

  • Unit (test/units/sessions/session-false.test.ts): SessionSchema parses false and rejects other falsy values; sessionConfigToManifest(false) returns undefined; the disabled provider registers no session (leaving Astro.session undefined) and marks the feature used.
  • Integration (test/session-false.test.ts): routes that never read Astro.session are unaffected; a route that reads Astro.session under session: false gets undefined (200, not a 500); the user's own ./session/provider.js import is not hijacked by the plugin; the built SSR output contains no createStorage and no class AstroSession.
  • Integration (test/session-tree-shake.test.ts): with no session config and an adapter that wires no driver, Astro.session is undefined and the runtime + unstorage are tree-shaken; with a configured driver, Astro.session is available and the runtime + unstorage are retained (guards against over-shaking).

Bundle-size measurement

Built the session-tree-shake fixture with the test adapter (which wires no default driver), comparing no driver vs. a configured driver:

Mode Files Total bytes unstorage in bundle AstroSession class in bundle
no driver (no session config) 13 375,878 no no
session: { driver: 'fs' } 13 386,915 yes yes
delta −11,037 (−10.8 KiB, −2.9%)

This is the floor of the savings measured against a fixture where no adapter auto-wires a driver. On Cloudflare/Netlify/Node with session: false, the adapter would otherwise also wire its driver (Cloudflare KV / Netlify Blobs / fs-lite) into the bundle, so the real-world delta on those targets is larger.

Docs

withastro/docs#14251

@changeset-bot

changeset-bot Bot commented May 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: de80530

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 406 packages
Name Type
@astrojs/cloudflare Minor
@astrojs/netlify Minor
@astrojs/node Minor
astro Minor
@test/astro-cloudflare-node-prerender-mdx Patch
@test/astro-cloudflare Patch
@test/astro-cloudflare-allowed-hosts Patch
@test/astro-cloudflare-astro-dev-platform Patch
@test/astro-cloudflare-astro-env Patch
@test/astro-cloudflare-binding-image-service Patch
@test/astro-cloudflare-cache-provider-wait-until Patch
@test/astro-cloudflare-cache-provider Patch
@test/astro-cloudflare-client-address Patch
@test/astro-cloudflare-compile-custom-image-service Patch
@test/astro-cloudflare-compile-image-service Patch
@test/astro-cloudflare-custom-entryfile Patch
@test/astro-cloudflare-dev-image-endpoint Patch
@test/astro-cloudflare-external-image-service Patch
@test/astro-cloudflare-external-redirects Patch
@test/astro-cloudflare-internal-redirects Patch
@test/astro-cloudflare-no-output Patch
@test/astro-cloudflare-prerender-node-env Patch
@test/astro-cloudflare-prerender-queue-consumers Patch
@test/astro-cloudflare-prerender-styles Patch
@test/astro-cloudflare-prerenderer-errors Patch
@test/astro-cloudflare-prerenderer-render-error Patch
@test/routing-priority-cloudflare Patch
@test/cf-server-entry Patch
@test/astro-cloudflare-server-island-prerender-framework Patch
@test/astro-cloudflare-sessions Patch
@test/astro-cloudflare-sql-import Patch
@test/cf-ssr-deps Patch
@test/astro-cloudflare-static Patch
@test/astro-cloudflare-svelte-rune-deps Patch
@test/astro-cloudflare-top-level-return Patch
@test/cf-user-optimize-deps Patch
@test/astro-cloudflare-vite-plugin Patch
@test/astro-cloudflare-with-base Patch
@test/astro-cloudflare-with-react Patch
@test/astro-cloudflare-with-solid-js Patch
@test/astro-cloudflare-with-svelte Patch
@test/astro-cloudflare-with-vue Patch
@test/astro-cloudflare-wrangler-preview-platform Patch
@test/netlify-session Patch
@test/netlify-hosted-astro-project Patch
@e2e/actions-blog Patch
@e2e/actions-react-19 Patch
@e2e/csp-server-islands Patch
@e2e/i18n Patch
@e2e/server-islands-key Patch
@e2e/server-islands Patch
@e2e/view-transitions Patch
@test/client-address-node Patch
@test/live-loaders Patch
@test/request-signal Patch
@test/static-build-ssr Patch
@test/nodejs-api-route Patch
@test/nodejs-badurls Patch
@test/nodejs-encoded Patch
@test/nodejs-errors Patch
@test/nodejs-headers Patch
@test/nodejs-image Patch
@test/locals Patch
@test/node-middleware Patch
@test/nodejs-prerender-404-500 Patch
@test/nodejs-prerender Patch
@test/nodejs-prerendered-error-page-fetch Patch
@test/nodejs-preview-headers Patch
@test/redirects Patch
@test/node-sessions Patch
@test/ssr-assets-middleware Patch
@test/node-static-headers Patch
@test/node-trailingslash Patch
@test/url Patch
@test/well-known-locations Patch
@test/sitemap-ssr Patch
astro-benchmark Patch
@e2e/astro-linked-lib Patch
@e2e/astro-component Patch
@e2e/astro-envs Patch
@e2e/astro-island-hydration-error Patch
@e2e/content-collections Patch
@e2e/css Patch
@test/custom-client-directives Patch
@e2e/dev-toolbar Patch
@e2e/error-cyclic Patch
@e2e/error-sass Patch
@e2e/errors Patch
@e2e/hydration-race Patch
@test/nested-style-bug-e22e Patch
@e2e/preact-compat-component Patch
@e2e/preact-component Patch
@e2e/preact-lazy-component Patch
@e2e/prefetch Patch
@e2e/react-component Patch
@e2e/solid-circular Patch
@e2e/solid-component Patch
@e2e/solid-recurse Patch
@e2e/svelte-component Patch
@e2e/e2e-tailwindcss Patch
@e2e/ts-resolution Patch
@e2e/vue-component Patch
@performance/md Patch
@performance/mdoc Patch
@performance/mdx Patch
@test/0-css Patch
fake-astro-library Patch
@test/actions Patch
@test/alias-css-url Patch
@test/alias-path-alias-style Patch
@test/ts-paths-no-baseurl Patch
@test/aliases-tsconfig Patch
@test/aliases Patch
@test/api-routes Patch
@test/asset-query-params-chunks Patch
@test/asset-url-base Patch
@test/astro-pages Patch
@test/astro-assets-prefix Patch
@test/astro-assets Patch
@test/astro-basic Patch
@test/astro-check-errors Patch
@test/astro-check-no-errors Patch
@test/astro-check-watch Patch
@test/astro-children Patch
@test/astro-client-only Patch
@test/astro-component-bundling Patch
@test/astro-component-code Patch
@test/astro-css-bundling Patch
@test/astro-dev-headers Patch
@test/astro-dev-http2 Patch
@test/astro-doctype Patch
@test/astro-dynamic Patch
@test/astro-env-content-collections Patch
@test/astro-env-required-public Patch
@test/astro-env-server-fail Patch
@test/astro-env-server-secret Patch
@test/astro-env Patch
@test/astro-envs Patch
@test/astro-expr Patch
@test/astro-get-static-paths Patch
@test/astro-head Patch
@test/astro-manifest-client-script Patch
@test/astro-manifest-invalid Patch
@test/astro-manifest Patch
@test/astro-markdown-frontmatter-injection Patch
@test/astro-markdown-plugins Patch
@test/astro-markdown-remarkRehype Patch
@test/astro-markdown-skiki-default-color Patch
@test/astro-markdown-skiki-langs Patch
@test/astro-markdown-skiki-themes-custom Patch
@test/astro-markdown-skiki-themes-integrated Patch
@test/astro-markdown-skiki-wrap-false Patch
@test/astro-markdown-skiki-wrap-null Patch
@test/astro-markdown-skiki-wrap-true Patch
@test/astro-markdown-url Patch
@test/astro-markdown Patch
@test/astro-mode Patch
@test/astro-page-directory-url Patch
@test/astro-partial-html Patch
@test/astro-preview-allowed-hosts Patch
@test/astro-preview-headers Patch
@test/astro-public Patch
@test/astro-script-template-dedup Patch
@test/astro-scripts Patch
@test/astro-slots-nested Patch
@test/concurrency Patch
@test/build-readonly-file Patch
@test/cache-memory-query-include Patch
@test/cache-memory-query Patch
@test/client-only-child-styles Patch
@test/client-only-css-chunk-leak Patch
@test/code-component Patch
@test/component-library Patch
@test/config-vite-css-target-no-minify Patch
@test/config-vite-css-target Patch
@test/config-vite Patch
@test/react-container Patch
@test/content-with-spaces-in-folder-name Patch
@test/content-collection-picture-render Patch
@example/content-collection-references Patch
@test/content-collection-tla-svg Patch
@test/content-collections-base Patch
@test/content-collections-empty-dir Patch
@test/content-collections-empty-md-file Patch
@test/content-collections-image-hmr Patch
@test/content-collections-mutation Patch
@test/content-collections-number-id Patch
@test/content-collections-type-inference Patch
@test/content-collections-with-config-mjs Patch
@test/content-collections Patch
@test/content-frontmatter Patch
@test/content-intellisense Patch
@test/content-layer-loader-schema-function Patch
@test/content-layer-remark-plugins Patch
@test/content-layer Patch
@test/content-ssr-integration Patch
@test/content-static-paths-integration Patch
@test/content Patch
@test/core-image-data-url Patch
@test/core-image-deletion-ssr Patch
@test/core-image-deletion Patch
@test/core-image-errors Patch
@test/core-image-fs-config Patch
@test/core-image-remark-infersize Patch
@test/core-image-layout Patch
@test/core-image-picture-emit-file Patch
@test/core-image-remark-imgattr Patch
@test/core-image-ssg Patch
@test/core-image-ssr Patch
@test/core-image-svg-in-client Patch
@test/core-image-svg Patch
@test/core-image-unconventional-settings Patch
@test/core-image Patch
@test/csp-adapter Patch
@test/csp-fonts Patch
@test/csp Patch
@test/css-assets Patch
@test/css-dangling-references Patch
@test/css-deduplication Patch
@test/css-double-bundle Patch
@test/css-dynamic-import-dev Patch
@test/css-import-as-inline Patch
@test/css-inline-stylesheets Patch
@test/css-no-code-split Patch
@test/css-path-case Patch
@test/css-pure-chunk-query-params Patch
@test/css-server-output-dedup Patch
@test/custom-404-injected-from-dep Patch
@test/custom-404-pkg Patch
custom-fetch-error-pages Patch
@test/custom-renderer Patch
@test/data-collections-schema Patch
@test/data-collections Patch
@test/debug-component Patch
@test/dev-container Patch
@test/dev-render Patch
@test/dev-request-url Patch
@test/dynamic-endpoint-collision Patch
@test/dynamic-route-build-file Patch
@test/endpoint-routing Patch
@test/error-bad-js Patch
@test/error-build-location Patch
@test/error-non-error Patch
@test/extension-matching Patch
@test/fetch Patch
@test/fonts Patch
@test/astro-fontsource-package Patch
@test/get-static-paths-pages Patch
@test/glob-pages-css Patch
@test/head-propagation-prerender-env Patch
@test/hmr-markdown Patch
@test/hmr-new-page Patch
@test/hmr-slots-render Patch
@test/hoisted-imports Patch
@test/html-component Patch
@test/html-escape Patch
@test/html-page Patch
@test/html-slots Patch
@test/hydration-race Patch
@test/i18n-client-import Patch
@test/i18n-css-leak-basic Patch
@test/import-ts-with-js Patch
@test/impostor-md-file Patch
@test/integration-add-page-extension Patch
@test/integration-server-setup Patch
@test/jsx-queue-rendering Patch
@test/large-array-solid Patch
@test/legacy-collections-backwards-compat Patch
@test/lightningcss-css-modules-content Patch
@test/lightningcss-scoped-nesting Patch
@test/markdown Patch
@test/middleware-dev Patch
@test/middleware-full-ssr Patch
@test/middleware-no-user-middlewaqre Patch
@test/middleware-tailwind Patch
@test/minification-html-default Patch
@test/minification-html-jsx Patch
@test/minification-html Patch
@test/non-ascii-path Patch
@test/non-html-pages Patch
@test/page-format Patch
@test/page-level-styles Patch
@test/parallel-components Patch
@test/partials-css-boundary Patch
@test/partials Patch
@test/passthrough-image-service Patch
@test/postcss Patch
@test/preact-compat-component Patch
@test/preact-component Patch
@test/remote-css Patch
@test/reuse-injected-entrypoint Patch
@test/root-srcdir-css Patch
@test/scoped-style-strategy Patch
@test/server-entry-fake-adapter Patch
@test/server-entry Patch
@test/server-islands-hybrid Patch
@test/server-islands-ssr Patch
@test/session-false Patch
@test/session-tree-shake Patch
@test/sessions Patch
@test/slots-preact Patch
@test/slots-react Patch
@test/slots-solid Patch
@test/slots-svelte Patch
@test/slots-vue Patch
@test/solid-component Patch
@test/sourcemap Patch
@test/space-in-folder-name Patch
@test/special-chars-in-component-imports Patch
@test/ssr-assets Patch
@test/ssr-dynamic Patch
@test/ssr-partytown Patch
@test/ssr-prerender-get-static-paths Patch
@test/ssr-prerender Patch
@test/ssr-preview Patch
@test/ssr-renderers-static-vue Patch
@test/ssr-request Patch
@test/ssr-hoisted-script Patch
@test/ssr-scripts Patch
@test/static-build-code-component Patch
@test/static-build-dir Patch
@test/static-build-frameworks Patch
@test/static-build-page-url-format Patch
@test/static-build Patch
@test/static-redirect Patch
@test/svelte-component Patch
@test/svg-deduplication Patch
@test/tailwindcss Patch
@e2e/third-party-astro Patch
@test/url-import-suffix Patch
@test/view-transitions Patch
@test/virtual-astro-file Patch
@test/vite-virtual-modules Patch
@test/vitest Patch
@test/vue-component Patch
@test/vue-with-multi-renderer Patch
@test/alpinejs-basics Patch
@test/alpinejs-directive Patch
@test/alpinejs-plugin-script-import Patch
@test/markdoc-content-collections Patch
@test/content-layer-markdoc Patch
@test/headings-custom Patch
@test/headings Patch
@test/image-assets-custom Patch
@test/image-assets Patch
@test/markdoc-propagated-assets Patch
@test/markdoc-render-with-space Patch
@test/markdoc-render-html Patch
@test/markdoc-render-null Patch
@test/markdoc-render-partials Patch
@test/markdoc-render-simple Patch
@test/markdoc-render-table-attrs Patch
@test/markdoc-render-this-context Patch
@test/markdoc-render-typographer Patch
@test/markdoc-render-with-components Patch
@test/markdoc-render-with-config Patch
@test/markdoc-render-with-extends-components Patch
@test/markdoc-render-with-indented-components Patch
@test/markdoc-render-with-transform Patch
@test/markdoc-variables Patch
@test/content-layer-rendering Patch
@test/mdx-css-head-mdx Patch
@test/image-remark-imgattr Patch
@test/mdx-astro-container-escape Patch
@test/mdx-frontmatter-injection Patch
@test/netlify-skew-protection Patch
@test/react-component Patch
@test/sitemap-chunks Patch
@test/sitemap-dynamic Patch
@test/sitemap-i18n-fallback Patch
@test/sitemap-static Patch
@test/sitemap-trailing-slash Patch
async-rendering Patch
conditional-rendering Patch
@test/empty-class Patch
svelte-prop-types Patch
@test/astro-vercel-basic Patch
@test/astro-vercel-image Patch
@test/astro-vercel-integration-assets Patch
@test/vercel-isr Patch
@test/vercel-max-duration Patch
@test/vercel-edge-middleware-with-edge-file Patch
@test/vercel-edge-middleware-without-edge-file Patch
@test/astro-vercel-no-output Patch
@test/astro-vercel-prerendered-error-pages Patch
@test/astro-vercel-redirects-serverless Patch
@test/astro-vercel-redirects Patch
@test/vercel-server-islands Patch
@test/astro-vercel-serverless-prerender Patch
@test/astro-vercel-serverless-with-dynamic-routes Patch
@test/astro-vercel-static-assets Patch
@test/vercel-static-headers Patch
@test/astro-vercel-static Patch
@test/vercel-streaming Patch
@test/astro-vercel-with-web-analytics-enabled-output-as-static Patch
vercel-hosted-astro-project Patch
@test/vue-app-entrypoint-async Patch
@test/vue-app-entrypoint-css Patch
@test/vue-app-entrypoint-no-export-default Patch
@test/vue-app-entrypoint-relative Patch
@test/vue-app-entrypoint-src-absolute Patch
@test/vue-app-entrypoint Patch
@test/vue-basics Patch
vue-prop-types Patch
@benchmark/adapter Major
@benchmark/timer Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added semver: minor Change triggers a `minor` release pkg: integration Related to any renderer integration (scope) pkg: astro Related to the core `astro` package (scope) docs pr and removed semver: minor Change triggers a `minor` release labels May 26, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is blocked because it contains a minor changeset. A reviewer will merge this at the next release if approved.

@codspeed-hq

codspeed-hq Bot commented May 26, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 21 untouched benchmarks


Comparing adamchal:session-false (de80530) with main (296e1b0)

Open in CodSpeed

@ascorbic ascorbic left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good idea to allow users to explicitly disable sessions, but I have some concerns with this implementation.

Changing the runtime behaviour so that accessing a disabled session throws, rather than making the session undefined, is a breaking change that would need a major, and I think is strictly worse DX. Why should user code need to care about whether the session configuration is false or undefined, and need to provide two code paths for it? It also leads to needing a lot of extra code in this PR. Lots of the code here seems to be devoted to threading through a signal about the difference between these, when the alternative is to just set it to undefined, which is already handled everywhere.

I think the idea of using Vite to enable tree-shaking the session module when it is disabled is good, but should also apply to session: undefined.

I would suggest the following:

  • Add the code that handles replacing all the session bundle in SSR when it's not enabled
  • Allow passing false to config.session. If there is no adapter set then this should behave exactly the same as not setting it, or setting it to undefined.
  • Your current changes to the adapters are good, and should stay.

Comment thread .changeset/session-false-opt-out.md Outdated
Adds a `session: false` config option that opts a project out of session
support entirely, and tree-shakes the session runtime (`AstroSession` +
`unstorage`) out of the SSR bundle for any project where no session driver
is wired.

- `session: false` is accepted by `SessionSchema` and threaded through so
  adapters skip auto-wiring their default driver (`@astrojs/cloudflare`,
  `@astrojs/netlify`, `@astrojs/node`).
- When no driver will be present at request time — `session: false`, no
  `session` config at all, or a `session` object without a driver —
  `Astro.session` (and `context.session`) is `undefined`, matching its
  existing `AstroSession | undefined` type. This keeps the established
  `if (Astro.session)` feature-detection contract instead of throwing.
- A new `astro:session-provider` Vite plugin swaps Astro's own
  `core/session/provider.js` for a runtime-free `provider-disabled.js`
  stub whenever no driver is wired, so Rollup drops `runtime.js` and
  `unstorage` from the bundle. Adapters wire their default driver during
  `astro:config:setup` (before `createVite`), so `config.session?.driver`
  reflects the final decision by resolve time — the same signal the
  driver virtual module uses. The swap is behavior-preserving: the real
  provider already resolves the session to `undefined` when no driver
  factory exists, so this only drops now-dead code.

```js title="astro.config.mjs"
import { defineConfig } from 'astro/config';

export default defineConfig({
  session: false,
});
```

Projects that already wire a session driver see no behavior change; the
runtime is retained whenever a driver is configured.
@matthewp

Copy link
Copy Markdown
Contributor

Marking this for 7.2

@matthewp matthewp added this to the 7.2 milestone Jul 24, 2026
adamchal added a commit to adamchal/docs that referenced this pull request Jul 24, 2026
haydenbleasel added a commit to haydenbleasel/blume that referenced this pull request Jul 25, 2026
…re builds

Without a configured session driver, @astrojs/cloudflare force-enables
KV-backed sessions and declares a SESSION kv_namespaces entry in the
generated wrangler config, so `wrangler deploy` demands a real KV
namespace nothing reads; it also defaults images to the runtime
Cloudflare Images binding. Blume never reads `Astro.session` and every
HTML route prerenders (the only server routes are API endpoints), so the
generated Astro config now sets an inert in-memory session driver and
`imageService: "compile"`, which pre-optimizes images at build time.

The memory driver's entrypoint (unstorage) resolves relative to Astro's
own session vite-plugin, so no dependency mirroring is needed. Once
withastro/astro#16871 ships a first-class session opt-out in the
supported range, the memory driver can be replaced with it.

Resolves #117
@ematipico

ematipico commented Jul 28, 2026

Copy link
Copy Markdown
Member

@adamchal here some AI generated findings you might want to look at. Take them with a pinch of salt. The skill is still very new, and it's AI.


Findings

  • [medium][correctness] packages/astro/src/core/session/vite-plugin.ts:103 - Provider matching fails with preserved symlinks. Node canonicalizes import.meta.url, while Vite can preserve pnpm/workspace symlink paths via vite.resolve.preserveSymlinks. Since normalizePath() does not resolve symlinks, the paths differ and the real provider remains bundled. Canonicalize both paths consistently and test this configuration.
  • [medium][correctness] packages/astro/src/core/session/vite-plugin.ts:92 - session: false remains indistinguishable from missing configuration at runtime. The disabled provider registers no session, causing FetchState to emit its “no session storage is configured” warning on every request that feature-detects Astro.session. Preserve the explicit disabled state or provide a silent undefined session for this case.
  • [medium][tests] packages/astro/test/session-false.test.ts:14 - Official adapter opt-out behavior is untested. The test adapter never supplies a default session driver, so these tests still pass if the Cloudflare, Netlify, or Node guards regress. Add adapter-level tests asserting session: false prevents driver and resource wiring.

adamchal added 2 commits July 28, 2026 16:40
The `astro:session-provider` plugin compared Vite's resolved id against a
path derived from `import.meta.url`. Node's ESM loader canonicalizes
`import.meta.url`, but Vite only resolves symlinks when
`resolve.preserveSymlinks` is false (the default). Under
`preserveSymlinks: true`, a pnpm or workspace link makes the two strings
differ even though they name the same file, so the redirect to
`provider-disabled.js` silently never happened and the session runtime
stayed in the SSR bundle.

Canonicalize both sides via `realpathSync` before comparing, falling back
to a plain compare for ids that are not real files (bare specifiers,
virtual modules). The cheap suffix prefilter now runs first so the added
`realpathSync` never touches the filesystem for unrelated imports.
The `session: false` tests used the test adapter, which never supplies a
default session driver, so they passed whether or not the Cloudflare,
Netlify, and Node guards were present.

Drive each adapter's `astro:config:setup` hook with a mock context and
assert that `session: false` leaves the config untouched and wires no
driver, that a user-supplied driver is still respected, and that the
adapter default is still wired when sessions are left unconfigured. For
Cloudflare, also assert the config customizer provisions no session KV
namespace when the driver is not needed.
@adamchal

Copy link
Copy Markdown
Contributor Author

@ematipico addressed the first and third bullet: both sides of the path comparison now go through realpathSync, and each adapter now has a test asserting session: false wires no driver. Left the second bullet as-is since that warning fires identically for session: undefined with no adapter driver. It’s existing behavior, and making false distinguishable from unset is a hole rabbit hole that @ascorbic pulled me out of.

The `session: false` tests for `@astrojs/node` built their mock project root
from a hardcoded `file:///project/`. That is only absolute on POSIX, so on
Windows the adapter's `fileURLToPath(new URL('sessions', config.cacheDir))`
threw `ERR_INVALID_FILE_URL_PATH`, failing the default-driver test. The other
two cases short-circuit before that call, which is why only one test broke.

Derive the root with `resolve` plus `pathToFileURL` so it carries a drive
letter on Windows. Unlike the Cloudflare and Netlify tests, this hook only
reads strings off the root, so it does not need a real directory on disk.
@ematipico
ematipico dismissed stale reviews from ascorbic and github-actions[bot] August 5, 2026 09:47

Addressed

@ematipico
ematipico merged commit 90c98ae into withastro:main Aug 5, 2026
47 of 48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs pr pkg: astro Related to the core `astro` package (scope) pkg: integration Related to any renderer integration (scope)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants