Request scope
Every request gets a child container on event.locals.container, also reachable through AsyncLocalStorage.
boot() installs contextHandle(container) as the first SvelteKit handle. For each request it:
- creates
app.scope(), a child of the root container; - sets it on
event.locals.container; - runs the rest of the pipeline inside
withScope({ container, event }, ...), so code that never receiveseventcan still find the scope.
The wrappers pass container to your handlers, so most code never needs the helpers below.
#Helpers
| Function | Use |
|---|---|
getScope() |
The current { container, event } scope, or undefined outside a request. |
getContainer() |
The current request container; throws when called outside a request. |
withScope(scope, fn) |
Run fn with a given scope. contextHandle calls this; tests can too. |
contextHandle(app) |
The handle itself, for apps that assemble their own handle without boot(). |
errorHandle() |
The default handleError. |
A factory registered on the root container can read the request through the scope. This is how the demo binds a Cloudflare D1 database that only exists on event.platform:
app.bind 'db', =>
db := getScope()?.event?.platform?.env?.DB
throw new Error 'D1 binding `DB` is missing' unless db
db#Adding your own handle
Pass extraHandle to boot(); the handles run after the context handle, so event.locals.container is already set. A typical auth handle resolves a session and sets event.locals.user, which the wrappers expose as user.
#Platform note
The scope uses AsyncLocalStorage from node:async_hooks. On Cloudflare Workers that requires the nodejs_als and nodejs_compat compatibility flags in wrangler.toml; see Deploy to Cloudflare.