deplaneDocs Dashboard

Databases

Managed Postgres next to your apps (Postgres 17, or 18 where Deplane offers it), backed up continuously, with point-in-time restore.

Create and attach

In the dashboard, open Databases, name the database and pick a size (and, where Deplane offers more than one, a Postgres version), or run deplane db create main (--version 18 for Postgres 18; see Postgres versions). It is ready in about a minute. Then attach it to an app (deplane db attach main --app shop): the app gets a DATABASE_URL variable and rolls out a new release with it, without downtime.

postgres://app:…@pg--main:5432/app

For a cache or a job queue, see Redis. For an app that needs MySQL, see MySQL. For analytics and event data, see ClickHouse®.

Use it like any Postgres URL, for example new Pool({ connectionString: process.env.DATABASE_URL }) in Node or psycopg.connect(os.environ["DATABASE_URL"]) in Python. The Notes + Postgres template does all of this in one click.

How it runs

Postgres versions

New databases run Postgres 17 unless you choose 18: the Postgres list next to Size on the Databases page (shown where Deplane offers 18), deplane db create NAME --version 18, "version": "18" in the API, or version in the create_database tool for AI assistants. Where 18 is not offered yet, asking for it is refused with postgres_version_unavailable and nothing is created.

Upgrading a 17 database to 18. There is no in-place upgrade: a database never changes version. The way up is a copy into a new Postgres 18 database, then deplane db switch. Copying from one of your Deplane databases into another is not self-service yet: the importer only reads databases it can reach over the internet, and Deplane databases are never reachable from there. Until it is, email support@deplane.io to plan the move.

Import from another host

A database you run elsewhere (Heroku, Render, Railway, Fly, RDS, Supabase, Neon or your own server) can be copied into a new Deplane database from Databases, Import a database, or with deplane db import. Deplane can keep the copy in sync until you are ready to switch. See Import a Postgres database.

Live copy and failover

Every database on your team has a live copy on another server, kept up to date as the database writes. (Pull request preview databases have none: they are free and short-lived.) If the server that runs the database goes down, the live copy takes over. This takes about 45 seconds. Your data is not lost: the copy has every committed write.

The database page in the dashboard shows the state of the copy, and deplane db shows it in the COPY column (live, none, or – when there is no copy to show):

Deplane also restarts the apps attached to the database when it fails over after a server went down. They open new connections to the new primary without you doing anything. A web process restarts one instance at a time, so the others keep serving. Workers stop and start all at once, so they are briefly down.

Right after a failover, the first writes can fail for a few seconds with cannot execute ... in a read-only transaction (a connection that was open before the failover). Retry them. Connections that are dead (the server is gone) can hang until a timeout, so set timeouts in your app's connection pool. Recommended settings:

Node (pg):

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  connectionTimeoutMillis: 5000,  // give up on a new connection after 5 s
  query_timeout: 30000,           // fail a query that hangs after 30 s
  idleTimeoutMillis: 30000,       // drop idle connections after 30 s
  keepAlive: true,                // notice a dead connection
});
pool.on("error", () => {});       // an idle connection that breaks must not crash the app

Python (psycopg):

conn = psycopg.connect(
    os.environ["DATABASE_URL"],
    connect_timeout=5,
    keepalives=1, keepalives_idle=30, keepalives_interval=10, keepalives_count=3,
)

Go (pgx):

cfg, _ := pgxpool.ParseConfig(os.Getenv("DATABASE_URL"))
cfg.ConnConfig.ConnectTimeout = 5 * time.Second
cfg.HealthCheckPeriod = 15 * time.Second // replace broken idle connections
cfg.MaxConnLifetime = time.Hour
pool, _ := pgxpool.NewWithConfig(ctx, cfg)

Limits

Your plan sets how many databases your team can have: 1 on Free, 2 on Hobby, 5 on Pro, 15 on Team (see limit_databases). Pull request preview databases do not count. A database counts against your plan as one instance of its size (small: ½ CPU and 512 MB; medium: 1 CPU and 1 GB; large: 2 CPU and 2 GB). The live copy is ours: it does not count against your plan. An app uses one database at a time as DATABASE_URL. Backups are kept for your plan's backup window: 1 day on Free, 7 days on Hobby, 14 on Pro. Moving to a plan with a shorter window deletes backups older than the new window, and deleted databases past it, at the next hourly cleanup. See Limits.

Backups and restore

Every database is backed up continuously: Deplane keeps its change log as it happens and takes a full copy every night, encrypted with a key of that database alone. You can restore it to any second in your plan's backup window (1 day on Free, up to 90 days on Enterprise), up to about a minute ago.

Where the backups are: on Deplane's control server, a different server from the database's, and a second copy on a separate backup server, pulled every 15 minutes. The backup server takes the copies itself: no other Deplane server holds a key that can change or delete them. Both are in the same region as your database (fra, Germany), still encrypted per database. If you need an export you hold yourself, run pg_dump from a worker or cron job.

The backup status shows on the database:

Times in the dashboard and in error messages are in UTC.

Restore

A restore never changes the original: it creates a new database at the moment you pick, which you check and then switch your apps to.

Restoring, switching and deleting a database each need their own fresh confirmation with your passkey (from the last 5 minutes, used up by the action): the dashboard asks for a tap, and the CLI shows a link and a code to approve in your browser. A stolen CLI login alone cannot do them, and CI tokens and AI tools cannot do them at all.

The restored database counts toward your plan like any other database, and needs a free place in your plan's databases. When many restores run on the platform at once, a new one waits a few minutes for its turn to download the full copy. A database needs two disks on the platform, one for each copy. If there is no free pair, creating or restoring a database is refused at once with database_capacity; try again later.

Deleted databases

A deleted database keeps its backups for your plan's backup window. Restore it from Recently deleted on the Databases page, or with deplane db restore main --deleted --at latest. It comes back as a new database (--to NAME, or main-restored-HHMM). After the window, the backups and their key are deleted for good.

Preview databases

Pull request previews can get their own empty databases: turn on "Give each preview its own empty database" in the app's GitHub settings (see GitHub). They are not on the Databases page, do not count toward your plan or its databases, are capped at 3 per team, are never backed up, and are deleted for good with their preview.

This page is also available as Markdown. AI agents can start at /llms.txt.