Public routes read the session store on every anonymous request (~250 ms on Cloudflare KV)

Open Beginner friendly
#3,702 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
1/5
Estimated time
Under an hour
Newbie friendliness
88/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active

Research direction

The guard belongs in handlePublicRouteAuth in dist/astro/middleware/auth.mjs; read that file alongside the already-correct dist/astro/middleware.mjs, which checks cookies.get("astro-session") before calling resolveSessionUser. Add the same cookie check at the top of handlePublicRouteAuth so anonymous requests short-circuit to next(), then rerun the anonymous public-page timing from the issue to confirm the KV read is gone. Related history is #1538, which introduced resolveSessionUser.

Written by the indexing model from the issue text.

Description

area/auth area/cloudflare bot:awaiting-approval bot:bug
Description

handlePublicRouteAuth in dist/astro/middleware/auth.mjs calls resolveSessionUser(session) for every public route, whether or not the request carries a session cookie:

async function handlePublicRouteAuth(context, next) {
	const { locals, session } = context;
	const { emdash } = locals;
	try {
		const sessionUser = await resolveSessionUser(session);

With no astro-session cookie, Astro generates a fresh session id, so session.get("user") looks up a key that cannot exist. On Cloudflare Workers with the session driver on KV, a read of a never-written key is not served from the colo cache. We measured 248-283 ms per anonymous render (warm isolates, Tokyo colo), against 4-10 ms for a key that exists. That wait sits in front of every anonymous page render, before any site middleware or page code runs.

The main middleware (dist/astro/middleware.mjs) already skips the lookup in this case:

const hasSessionCookie = cookies.get("astro-session") !== void 0;
const sessionUser = context.isPrerendered || !hasSessionCookie ? null : await resolveSessionUser(context.session);

Expected: handlePublicRouteAuth makes the same check. One line fixes it:

if (context.cookies.get("astro-session") === void 0) return next();

Without the cookie the old read could never find a user, so the guard changes no behaviour except the latency. Logged-in requests carry the cookie and keep the read. Related: #1538 added resolveSessionUser and its timeout backstop, but not a cookie check on this path.

Steps to reproduce
  1. Deploy an EmDash site to Cloudflare Workers with the default SESSION KV binding for Astro sessions.
  2. Request any public page anonymously (no cookies), with a cache-busting query so it renders.
  3. Time the gap between the start of EmDash's middleware chain and the first line of a site middleware that runs after it (or compare the Server-Timing db.first offset). On our site it is ~250 ms on every anonymous render.
  4. Add the guard above to handlePublicRouteAuth and repeat. The gap disappears.
Environment
  • emdash version: 0.32.0 (1.0.1 has the same handlePublicRouteAuth)
  • Astro 6.1.10, @astrojs/cloudflare 13
  • Runtime: Cloudflare Workers (compatibility_date 2026-02-24), Astro sessions on KV
  • OS: not applicable
Screenshots

Not applicable.

Logs / error output
No error. Timing only: gap before site middleware 251-263 ms (warm), KV get of a random nonexistent key 248-283 ms, KV get of an existing key 4-10 ms, measured in the same requests.

We carry the guard as a pnpm patch for now and are happy to open a PR.

Dominant language
TypeScript
Stars
13.4k
Forks
1.3k
Avg merge
2d 14h
Merged PRs (30d)
365

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from emdash-cms/emdash

All issues in emdash-cms/emdash

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.