Connections explained

A connection is one keypair, for one project, in one environment.

Not per Worker. Not per customer account. Not one credential for everything you own.

Per environment, because environments are the isolation boundary

Connecting an environment is the act, connection scopes is what one grants, and the control-plane seam is what it registers against.

A staging credential cannot reach production. The environment is stored on the connection row, and your Worker checks it against its own environment on every call — so a token minted for staging is refused by a production Worker even if somebody has both.

That is the isolation people expect from environments, made real at the credential rather than assumed from configuration.

It also means the blast radius of a leak is one environment of one project. Rotation and revocation are naturally scoped to the same thing.

Never per Worker, and this is the part people ask about

Workers share a resource by declaring the same binding name. One user record lives in one D1 that several Workers touch.

So a per-Worker credential would produce a management view where a user is visible in one pane and absent from another — not because of permissions, but because you happened to connect to the Worker that does not bind that database.

And a second connection to a sibling Worker would be a second credential onto the same rows. Two keys, two revocations to remember, one dataset.

So the administrative surface is composed on one Worker per project, and the connection targets that one. In a project with several Workers, pithy dashboard connect refuses the ambiguity and asks which one rather than guessing — and a Worker composing no control-plane seam is refused outright, because there is nothing there to connect to.

--worker on the other subcommands is only how the CLI finds the app database. The row is keyed on the environment.

Several projects, several connections

A customer may register as many projects as they run, each with its own keypair. The dashboard resolves how many you have and offers a picker when there is more than one; a single project needs no ceremony.

What a connection stores, on your side

Every one of these is a column in your D1:

FieldWhat it is
The connection idA UUID, because it is the token audience and therefore externally exposed
The environmentChecked against your Worker’s own on every call
The issuerThe exact origin every token from this connection must carry
The Worker URLCaptured at connect, and re-pointed with --update when a domain moves
The base pathWhere this Worker mounts the seam
The scopesWhat was granted. Your Worker enforces this row and nothing else
The keysEvery key this connection may sign with, current and superseded

Why the base path is stored

It is the one address a client cannot discover, because it is the manifest’s own address.

Everything else is discoverable: each admin route carries its fully mounted path in the manifest, so no client hardcodes a capability’s mount point. But if you mounted the seam somewhere other than the default and the client had to assume, you would register cleanly, pass the connection test — called at that same assumed path — and then 404 on every real call, with whoever is debugging it looking at the wrong problem entirely.

The address changes, and that is expected

A custom domain, a renamed Worker, a moved environment. Any of those breaks the connection, and the repair is a re-point rather than a rebuild:

pithy dashboard connect --env prod --update --worker-url https://api.example.com

A connection whose test call fails surfaces as needs reconnecting, never as a silent dead link.

The address is resolved, not demanded

connect does not ask you for a URL. It resolves one from your project — the Worker’s domain declaration for that environment, then its route, then a hand-set base URL var — and prints what it found and where it came from before registering anything.

--worker-url overrides it, and is the only way to say so when a proxy fronts your Worker, which is an address no config knows.

ESC