Managed Postgres
Managed Postgres on Lizard is a PostgreSQL database that you add to a project with lizard add postgres. New databases run PostgreSQL 18 by default. Lizard stores the connection string in DATABASE_URL and its parts in PGHOST, PGPORT, PGUSER, PGPASSWORD and PGDATABASE. Connect services with a reference such as ${{postgres.DATABASE_PRIVATE_URL}}. The database uses the same CPU, memory and storage rates as apps. You can query it in the dashboard’s SQL editor. For an overview and prices, see the Managed Postgres page.
Provision
lizard add postgresThe first Postgres addon is named postgres, so ${{postgres.DATABASE_URL}} works immediately.
Environment variables
The addon exposes a standard set of connection variables:
| Variable | Description |
|---|---|
DATABASE_URL | Full connection string over the public endpoint (postgresql://…) |
DATABASE_PRIVATE_URL | Connection string over the project’s private network (<name>.lizard.internal:5432) |
PGHOST | Host |
PGPORT | Port |
PGUSER | User |
PGPASSWORD | Password |
PGDATABASE | Database name |
POSTGRES_USER | Alias for the user |
POSTGRES_DB | Alias for the database |
POSTGRES_PASSWORD | Alias for the password |
Postgres connection string
Each database has two connection strings. Both use the user postgres and the database postgres:
| Variable | Use it from | Format |
|---|---|---|
DATABASE_PRIVATE_URL | Services in the same project | postgresql://postgres:<password>@<name>.lizard.internal:5432/postgres |
DATABASE_URL | Your machine, CI, or a service in another project | postgresql://postgres:<password>@<host>:<port>/postgres |
<name> is the database’s name in the project, postgres for the first one. Lizard assigns the public host and port when it creates the database, so read them from DATABASE_URL, PGHOST and PGPORT rather than typing them. The private address works only inside the project; see private networking.
Most drivers take the string as is:
// Node.js with pg
import pg from 'pg';
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });# Python with psycopg
import os, psycopg
conn = psycopg.connect(os.environ["DATABASE_URL"])psql and other libpq tools read the PG* variables, so they connect with no arguments.
How do I see the connection string?
- Dashboard: open the database in your project. The Overview tab shows
DATABASE_URLand the private URL with copy buttons. The Secrets tab lists every connection variable and the${{…}}reference to paste into a service. - CLI:
lizard run --service postgres -- printenv DATABASE_URLprints the public string. It contains the password, so do not paste it into logs or chat.
The string is a credential. Point services at it with a reference instead of copying it into a secret, so they get the current value on every deploy.
Connect a service
Reference the private connection string from the consumer service and redeploy:
lizard secrets set DATABASE_URL='${{postgres.DATABASE_PRIVATE_URL}}' --service api
lizard redeploy --service apiThe reference resolves at deploy time, so every consumer picks up the addon’s current values on its next deploy. Use DATABASE_URL instead for clients outside the project. Every service in the project also gets the addon’s public DATABASE_URL at the lowest precedence; an explicit reference overrides it.
Verify connectivity from your machine without printing the connection string:
lizard run --service postgres -- sh -c 'psql "$DATABASE_URL" -c "SELECT 1"'lizard run --service postgres runs the command on your machine with the database’s public connection values, so it needs psql installed locally. lizard run --service api would pass ${{…}} references through as literal text; see lizard run.
Run migrations on deploy
Use a pre-deploy command for migrations. It runs only when a start command is also set, as sh -c "<pre> && exec <start>" at the start of every container: each replica, each restart. Make migrations safe to run many times and at the same time, and compatible with both the old and new application version:
lizard service set api --set preDeployCommand="npm run migrate" --set startCommand="npm start"
lizard redeploy --service apiFor a Django app the command is python manage.py migrate; see the Django guide and Python app hosting. The Umami and Flowise guides show complete apps on Managed Postgres.
Browse and query data
Open the Postgres editor in the dashboard (lizard open) to run SQL and browse tables directly. For ad-hoc local work, run a command with the addon’s connection values:
lizard run --service postgres -- sh -c 'exec psql "$DATABASE_URL"'Grow storage
Data volumes are grow-only:
lizard scale --service postgres --storage 8192Multiple databases
Adding a second Postgres gives it a generated name (e.g. postgres-autumn-bear). Reference it explicitly:
lizard add postgres
lizard secrets set ANALYTICS_URL='${{postgres-autumn-bear.DATABASE_PRIVATE_URL}}' --service apiBackups and restore
Do not assume scheduled backups or point-in-time recovery. Before a risky migration, export the database yourself and test the restore in a separate database. For example, with pg_dump 18 or newer installed locally:
lizard run --service postgres -- sh -c 'pg_dump "$DATABASE_URL" > backup.sql'See storage and recovery for a restore plan.
See also
- Managed Addons: naming, references, and the dashboard browsers.
- Cross-Service References: reference syntax and resolution.
Updated