Connections
A connection says one thing: this app may use this service, at this level. It is the single record behind everything a deployed app is handed — its database URL, its bucket credentials, its auth variables, its platform key — and, for a database, the network path that lets it open a connection at all.
A service is not handed to every app of its project. An app reaches a database, a bucket or an auth app once you connect the two, and stops reaching it the moment you disconnect them.
What can be connected
The connectable services are a project’s databases, storage buckets and auth apps. The other end is always a site — one deployable app of the project. The level says how much the connection grants:
| Service | Level | What the app gets |
|---|---|---|
| Database | read-only | Everything connect gives, except that the app’s own credential may only read |
| Database | connect | DATABASE_URL / MONGODB_URI — with the MONGODB_URL alias and the per-database names — plus the network policy that lets its pods reach the database |
| Bucket | read | Everything read-write gives, except that the app’s own key may only read the bucket |
| Bucket | read-write | STORAGE_ENDPOINT, STORAGE_ACCESS_KEY, STORAGE_SECRET_KEY, STORAGE_BUCKET, STORAGE_REGION |
| Auth app | client | ESPACETECH_AUTH_APP_ID, ESPACETECH_AUTH_URL, ESPACETECH_AUTH_PUBLIC_URL, ESPACETECH_AUTH_SERVER_KEY, and GHAYMA_AUTH_APP_ID for the build |
| Auth app | admin | Everything client gives, and the site’s managed GHAYMA_API_KEY may administer that auth app’s end users |
Every kind has two levels, listed weakest first. A connection made without a
level grants what a connection has always granted — connect for a database,
read-write for a bucket, client for an auth app — so the read-only levels are
something you ask for. See Read-only connections.
The managed platform key follows the levels
A site connected to a bucket, a database, or an auth app at admin is also
handed GHAYMA_API_KEY, a project API key the
platform mints for that site. Its capabilities are read straight off the
connections: storage for a bucket, databases for a database, and auth for
an auth app at admin — narrowed to exactly those apps, so a project’s second
auth app is never swept in. A read-only or read connection grants the same
capability as the full level: the level narrows the app’s own credential, not
the platform key. A site whose connections imply no capability — none
at all, or only an auth app at client — gets no key, and any key it still
holds is revoked.
When a connection applies
Connecting, disconnecting or changing a level reaches the running apps right away — the pods pick up the new values without a redeploy, and a database network policy converges within about two minutes. Every later deploy derives the same thing again, so a rollback gets exactly what a deploy gets.
All of these variables are derived, never stored. They do not appear in
ghayma env list, there is nothing to edit, and a value you set yourself
under one of these names is replaced by the platform’s. See
Automatically injected
variables.
Each app gets its own database credential
An app connected to a PostgreSQL database, or to a MongoDB database that
runs as a replica set, is not handed the database’s main user. The platform
creates a credential for that one connection — named c_ followed by eight
characters, like c_14bb37f4 — and that credential is what the app’s
DATABASE_URL or MONGODB_URI carries.
- Disconnecting drops only that app’s credential. Every other app on the database, and your own credentials, are untouched.
- Migrations still work across apps. On PostgreSQL every app connected at
level
connectacts as one shared owner role —<dbname>_rw— so a table created by one app’s migrations can be altered by another app’s. Creating tables, altering tables and types, creating schemas and creating trusted extensions all work as before. - Rotating the password leaves the apps alone.
ghayma db rotate— and the console’s rotate control — change the main user’s password only; apps keep working with their own credentials. To re-secret one app’s credential, see Rotating Credentials.
On MongoDB the c_… user holds the readWrite role on that one database and
nothing else, and it lands in MONGODB_URI and its MONGODB_URL alias.
ghayma db credentials, the console’s
credentials panel, the external URL and the pooled endpoint all still show the
database’s main user (u_<name>), on both engines. Apps get their own; a
system outside Ghayma should get its own too — a named
principal is the same c_… identity, with a level, an
optional source allowlist and its own revoke. To see what an app actually
receives, run ghayma env pull — so an app you
run on your machine uses the same credential the deployed one does.
Apps connected before this shipped switch to their own credential at their next deploy, or as soon as any connection on the project changes. Nothing is restarted for it.
Standalone MongoDB is the exception. A standalone instance — one created
with --replica-set=false, or an older database born standalone — has no
internal admin identity the platform can create users with, so its connected
apps are still handed the database’s shared user. Replica-set MongoDB, the
default today, gets per-connection users like PostgreSQL. And if a database is
stopped when you
connect an app, the connection is made with the shared credential; the app gets
its own once the database runs again.
Each app gets its own storage key
An app connected to a bucket is handed an S3 access key created for that one
connection. It arrives in STORAGE_ACCESS_KEY and STORAGE_SECRET_KEY — and in
the suffixed STORAGE_<NAME>_* names — in place of the bucket’s own key.
- That key reaches one bucket. It reads and writes that bucket and nothing else, and it can never delete the bucket or change its settings.
- Disconnecting deletes only that app’s key. The other apps, and the bucket’s own key, are untouched.
- Rotating leaves the apps alone.
ghayma storage rotate— and the console’s rotate control — roll the bucket’s own key only; apps keep working with theirs. To replace one app’s key, see Rotating Credentials.
ghayma storage credentials and the
console’s credentials panel still show the bucket’s own key. Apps get their
own; a tool outside Ghayma should get its own too — a named
principal is a key pair of its own, at read or
read-write, revocable alone. Read what an app actually receives with
ghayma env pull.
Apps connected before this shipped switch to their own key at their next deploy, or as soon as any connection on the project changes.
Read-only connections
A database connection can be read-only, and a bucket connection can be read.
The app keeps the same credential — the same name, the same password or key —
and only what it may do changes:
- PostgreSQL. The app’s role may
SELECTeverything the read-write apps’ shared owner group holds, including tables another app creates later. NoINSERT,UPDATE,DELETEor DDL. - MongoDB. The app’s user holds the
readrole on that database instead ofreadWrite. - Buckets. The app’s key may
GETandLIST;PUTandDELETEare refused.
The level changes nothing else. The network path to the database is the same, and
so is the set of injected variables — a read-only app still receives the full
DATABASE_URL or STORAGE_* set, its credential simply cannot write.
Connecting without a level is unchanged: a database connection starts at
connect and a bucket connection at read-write. Pick the read-only level when
you connect, or change it afterwards — the console and the CLI both change a
level in place, without disconnecting first.
ghayma connect database my-postgres --level read-only
ghayma connect bucket uploads --level readManage them in the console
There are two views of the same rows in the console — one per app, one per service. Use whichever matches the question you are asking.
What this app uses
Open Project → the site → Connections:
- Connected services lists the databases, buckets and auth apps this app may use, each with its level and, as chips, the variables the platform injects for it. Change a service’s level here, or Disconnect it.
- Connect a service lists the project’s other services, each with the variables connecting would add — pick a level, then Connect.
Databases and buckets carry the level picker on connected rows and in the Connect dialog, exactly as auth apps always have.
Those chips are variable names only; no value is ever shown. Read the values
with ghayma env pull.
Which apps use this service
The Access section on the database settings page, the bucket page and the auth app page lists every app of the project, connected or not, with the level of each connection. Connect, disconnect and change a level from there.
On a database or a bucket the same table also carries the named
principals outside Ghayma — rows badged external
rather than app — with their allowlist, expiry and status, and the actions to
add, rotate, revoke or re-allowlist one. An auth app’s external access is its
restricted project keys, so its Access list
shows those instead.
Raising an auth app to admin asks for confirmation, and the control says why:
admin lets this app manage all users of this auth app. Disconnecting asks
for confirmation too, and names the variables that will disappear from the
app.
Seeing connections needs the read role on the project; connecting, disconnecting and changing a level need write or above.
What a new service starts connected to
- A project with exactly one site — a new database, bucket or auth app is connected to that site as soon as it is created. Nothing to do.
- A project with several sites — the new service starts connected to nothing, and its page says so: Not connected to any app yet. Pick the apps that may use it. A guess would hand a database’s credentials, or an auth app’s server key, to the wrong app.
- A new site starts with no connections at all. Connect what it needs from its Connections tab.
From the API
The routes live under /api/v1 and take an account token or a dashboard
session. Reading needs the project read role, every mutation needs
write.
| Route | Does |
|---|---|
GET /projects/:id/connections | Every connection in the project. Filter with site_id, kind, resource_id |
GET /projects/:id/sites/:siteId/connections | One site’s connections, plus the services it could still be connected to |
PUT /projects/:id/sites/:siteId/connections | Replace a site’s whole set |
POST /projects/:id/sites/:siteId/connections | Connect one service, or change its level |
DELETE /projects/:id/sites/:siteId/connections/:kind/:resourceId | Disconnect one service |
A row is the same everywhere:
{
"site_id": "…",
"site_slug": "admin",
"kind": "auth_app",
"resource_id": "…",
"resource_name": "main-auth",
"level": "client",
"env_names": ["ESPACETECH_AUTH_APP_ID", "ESPACETECH_AUTH_URL", "…"],
"created_at": "2026-09-08T10:00:00Z"
}env_names is the exact set of variable names the platform injects into that
site for that connection — names, never values. The services a site could still
be connected to carry it too, so a UI can say what connecting would add. See
Connections.
The older per-service routes — GET/PUT /databases/:id/sites and
GET/PUT /storage/:id/sites — keep working and read and write these same
connections. Full reference: Connections.
A project API key cannot call these routes — they answer 403. A site’s
managed key is minted from its own connections, so a key able to change them
could widen what it may do.
From the CLI
ghayma db sites works exactly as before —
what it lists and edits is now a database connection, and --add makes one at
the default level, connect:
ghayma db sites my-postgres # which apps may use it
ghayma db sites my-postgres --add admin # connect the 'admin' appThe dedicated commands cover all three kinds, and read and write these same rows:
# Which apps may use which services
ghayma connections
ghayma connections --site admin
# Connect a service to an app — without --level, the kind's usual level
ghayma connect database my-postgres
ghayma connect bucket uploads --site admin
ghayma connect auth shop --level admin
# Connect at a read-only level, or move an existing connection down to one
ghayma connect database my-postgres --level read-only
ghayma connect bucket uploads --level read
# Stop an app using a service (asks first, unless --yes)
ghayma disconnect auth shop --site admin
# Write the site's effective variables — the derived ones included — to .env.local
ghayma env pull
# Tunnel the app's databases to this machine and write .env.local pointing at them
ghayma connect --localFull reference: Connections and ghayma env pull.