Conductor · architecture · database
For a dedicated-DB app, Conductor derives DATABASE_URL from the app's own provisioned container at deploy time — resolved on the box it's landing on — and never bakes it into the image, config, or repo. That one choice is what makes an app a portable unit.
DATABASE_URL is derived from <slug>-db at deploy, per box, secret-safe. An explicit operator DATABASE_URL always wins.The app holds no DB address. Its connection is resolved at deploy from the dedicated container on whatever box it lands on — so moving the app to another box just works: the deploy on the new box derives the new box's DSN automatically. Same container name, different machine, zero manual juggling. This is exactly what makes app-transfer's cut-over clean.
Same <slug>-db container name on both boxes; the deploy resolves the DSN for the box it targets. No connection string is ever moved by hand.
App#derived_database_url(server:) returns the dedicated container's DSN — appended by deploy_env_pairs and declared secret by deploy_secret_keys (so it's injected from .kamal/secrets).
def derived_database_url(server: self.server)
return nil unless dedicated_db?
return nil if env_variables.any? { |v| v.key == "DATABASE_URL" } # explicit wins
dedicated_database(server:)&.database_url
end
# → postgres://<user>:<pw>@<slug>-db:<port>/<name> (container DNS)
A shared-cluster app has a hand-set DATABASE_URL env var pointing at the shared Postgres. No derivation — and (today) not transferable until converted (SharedToDedicatedConverter) to the dedicated model.
Set DATABASE_URL as an app env var and it always wins — external/managed DB, a read-replica DSN, anything non-standard. derived_database_url returns nil and the derived path steps aside. No special mode; just presence of the var.
DATABASE_URL silently keeps talking to the old DB — the manual var wins. The converter deletes it on purpose.server: it uses the app's current server. In a transfer, always pass the box you mean.SharedToDedicatedConverter deletes the manual DATABASE_URL precisely so this derived path takes over once an app becomes dedicated.