Skip to Content
Framework GuidesConnections

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:

ServiceLevelWhat the app gets
Databaseread-onlyEverything connect gives, except that the app’s own credential may only read
DatabaseconnectDATABASE_URL / MONGODB_URI — with the MONGODB_URL alias and the per-database names — plus the network policy that lets its pods reach the database
BucketreadEverything read-write gives, except that the app’s own key may only read the bucket
Bucketread-writeSTORAGE_ENDPOINT, STORAGE_ACCESS_KEY, STORAGE_SECRET_KEY, STORAGE_BUCKET, STORAGE_REGION
Auth appclientESPACETECH_AUTH_APP_ID, ESPACETECH_AUTH_URL, ESPACETECH_AUTH_PUBLIC_URL, ESPACETECH_AUTH_SERVER_KEY, and GHAYMA_AUTH_APP_ID for the build
Auth appadminEverything 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 connect acts 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 SELECT everything the read-write apps’ shared owner group holds, including tables another app creates later. No INSERT, UPDATE, DELETE or DDL.
  • MongoDB. The app’s user holds the read role on that database instead of readWrite.
  • Buckets. The app’s key may GET and LIST; PUT and DELETE are 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 read

Manage 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.

RouteDoes
GET /projects/:id/connectionsEvery connection in the project. Filter with site_id, kind, resource_id
GET /projects/:id/sites/:siteId/connectionsOne site’s connections, plus the services it could still be connected to
PUT /projects/:id/sites/:siteId/connectionsReplace a site’s whole set
POST /projects/:id/sites/:siteId/connectionsConnect one service, or change its level
DELETE /projects/:id/sites/:siteId/connections/:kind/:resourceIdDisconnect 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' app

The 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 --local

Full reference: Connections and ghayma env pull.