Database
Database gives an application its own PostgreSQL database in each environment, with no database for you to set up. Each environment gets a database and its owner role, the role that owns it. Turn Zero Cloud provisions the development database and its owner role when the manifest first declares the service, on every application. On an application with one environment, production, the development database is used by local runs alone.
The production database is provisioned at the first deploy to production of an application with one environment, or at the first promote of one with two, made while the manifest declares the database. The application reaches each database through one connection setting. It changes its schema with migration files that it applies each time it starts.
Use it when
Use Database for structured records that need filtering, counting, joins, or transactional updates. Use Storage for file and blob contents.
Keep application preferences and other per-account records here as well. The Account client verifies identities and sessions and stores no such data.
What it provides
- A database and role for each environment, provisioned when the manifest declares
{"kind": "database"}. The platform provisions the development database and its owner role on a development server at manifest submission. It provisions the production database and its owner role on a production server of the same hosting cell at the first deploy to production or first promote, made while the manifest declares the kind. APP_DATABASE_URL, the environment's connection string. A deploy injects it into the running copy of the environment it reaches, whichread_statuslists. A promote injects it into the production environment's own container. Deploy an application lists it beside the other settings a deployed container receives.APP_DATABASE_CONNECTION_LIMIT, the plan'sconnection_limit, the client pool's maximum. The deploy, the promote, andrestart_applicationinject it beside the connection string, and the provision line writes it for a local run. A running copy keeps the value it started with until its environment's next deploy, promote, or restart.- The development connection facts. The provisioning response returns them. Over the HTTP API a first submission that names no
local_runalso returns the development role's credential, once. Through the Model Context Protocol (MCP) tools, and over the HTTP API where the submission nameslocal_run, the response showscredentials: withheld, and the provision line writes the local setting instead. The same response includesconnection_limit: the number of connections each process of the application may keep open at once, which sets the pool's maximum. - Credential rotation. A lost development credential is re-minted through
rotate_secreton the development scope over the HTTP API, and the provision line makes that call. The MCP tool refuses the re-mint withlocal_route_required: your tool callssubmit_manifestwithlocal_run: trueand runs the line it returns. The production credential is never returned. Apromote, or a deploy to production on an application with one environment, rotates it when the call includesrotate_database_credential: true. - A migration function,
applyMigrations, published as the npm package@turnzero/database. Use the library shows how to copy it intoapp/lib/database/, declare it asfile:lib/database, and install it withnpm install. Your application calls the function before it serves requests, with a query function tied to one database connection and a migration-file reader. - A migration ledger and an advisory lock, which the function uses as the next list describes.
- Isolation by database role on the shared server.
- Removal with the environment. On one environment or two,
delete_environmentdrops the development database and its owner role, and the next manifest submission provisions them again for local runs. Deleting the application drops both databases and their owner roles.
The migration function behaves as follows:
- It applies the files in order, each in its own transaction.
- It strips one byte-order mark (BOM) from the start of each file before it runs the file. A BOM anywhere else in the file is passed to the server as written.
- If a file fails, the earlier files stay applied, and the application must stop before serving.
- It also fails when it cannot release the lock at the end of an otherwise successful run.
- When it fails, release the connection it ran on with the error, as in
client.release(error). Thepgpool then discards that connection instead of reusing it. - A connection the function could not open, or one the server ended during the run, is a failover, not a failed file. The package's
bootWalkcalls the function again every second and stops once 120 seconds have passed since the first attempt.
The package ships a test double at @turnzero/database/testing. It is a pool with the pg.Pool shape over a PGlite engine your tests construct, with your migration files applied at construction. PGlite is a PostgreSQL build that runs inside the Node.js process, so the application's tests run offline with no development database. The engine package is @electric-sql/pglite, a development dependency at version 0.5.8, the version the double is tested against, and the double's declaration lists it. Test your application locally shows the double in use.
Each environment has its own database. A local run using the development environment file reaches the development database, from any address under the developer network rule, and never production's. Add a database explains connection targeting, the production rotation, and the limits of migrations applied at startup.
Availability
Version 0.10.2 is the package's current version, and list_library reports the version the platform currently publishes. The entry includes the testing subpath from version 0.5.0. The entry contains the package's product statement, its detailed contract, its integration guide, and the compiled migration function and failover pool. Your tool reads the integration guide with read_library_entry, giving name and file: "features/database/integration.md".
From version 0.10.0 the entry also includes a failover pool. A failover is the switch to a production server's standby, which can take up to 120 seconds to answer. It ends every open database session, and in Node.js an ended session your code does not listen for stops the process. createFailoverPool calls your factory, which builds the pg pool, and listens for those ended sessions, so the process keeps serving.
The pool also bounds each connection attempt at five seconds, so a request fails quickly instead of waiting out the switch. Your process entry still reads APP_DATABASE_CONNECTION_LIMIT and passes it to the pool as max. bootWalk runs the migration function at startup and retries it every second for up to 120 seconds. After that it fails with the code failover_window_ended. The integration guide shows both in use.
Three parts work today: provisioning; injecting the connection setting and the connection limit at the deploy, the promote, and the restart; and rotating the production credential on request. The platform serves no migration, snapshot, or restore action: a call to apply_migration or restore_snapshot answers 501 not_yet_provisioned, and a promote takes no snapshot.
Related feature packages
Storage stores files and blobs. Account verifies the identities your application records belong to. Billing is not in the library, and the Database migration function does not need it.