PostgreSQL
Local PostgreSQL server with deterministic ports and zero configuration
Stackpanel can manage a local PostgreSQL instance for your project. It runs on a deterministic port derived from your project name, so every team member gets the same connection string without coordination.
Enable PostgreSQL
stackpanel.globalServices.postgres = {
enable = true;
};That's it. The next time you enter your dev shell, PostgreSQL will be available. A database matching your project name is created automatically.
Connection Details
Once enabled, Stackpanel exports the connection details as environment variables:
| Variable | Example Value |
|---|---|
STACKPANEL_POSTGRES_PORT | 4237 |
PGHOST | localhost |
PGPORT | 4237 |
PGDATABASE | myapp |
You can use these in your application code directly:
stackpanel.devshell.env = {
DATABASE_URL = "postgresql://localhost:${toString config.stackpanel.ports.computed.postgres}/myapp";
};Or reference them at runtime:
psql # connects automatically using PG* environment variablesThe port is computed deterministically from your project name. It won't conflict with other Stackpanel projects or a system-wide PostgreSQL installation. See Deterministic Ports for how this works.
Managing the Service
PostgreSQL is managed through the Stackpanel service lifecycle. Use the CLI to control it:
# Start PostgreSQL
stackpanel services start postgres
# Stop it
stackpanel services stop postgres
# Check status
stackpanel services status
# View logs
stackpanel services logs postgres
# Restart after config changes
stackpanel services restart postgresYou can also manage services through Studio, which shows service status in real time.
Data Directory
PostgreSQL stores its data in a project-local directory so that each project has its own isolated database cluster:
.stack/state/services/postgres/data/This directory is gitignored by default. Deleting it resets the database to a clean state—useful when you want to start fresh.
Configuration Options
Custom Database Name
By default, a database is created with your project name. To use a different name:
stackpanel.globalServices.postgres = {
enable = true;
database = "my_custom_db";
};PostgreSQL Version
Stackpanel uses the PostgreSQL version provided by your Nixpkgs input. To pin a specific version:
stackpanel.globalServices.postgres = {
enable = true;
package = pkgs.postgresql_16;
};Available packages include postgresql_14, postgresql_15, postgresql_16, and postgresql_17 depending on your Nixpkgs revision.
Extensions
Enable PostgreSQL extensions by adding them to the package:
stackpanel.globalServices.postgres = {
enable = true;
package = pkgs.postgresql_16.withPackages (ps: [
ps.postgis
ps.pgvector
ps.pg_cron
]);
};Custom Configuration
Pass additional PostgreSQL configuration options:
stackpanel.globalServices.postgres = {
enable = true;
settings = {
log_statement = "all";
max_connections = "200";
shared_buffers = "256MB";
};
};Initial SQL
Run SQL on first database creation—useful for seeding schemas, creating roles, or enabling extensions:
stackpanel.globalServices.postgres = {
enable = true;
initialScript = ''
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE ROLE app_user WITH LOGIN PASSWORD 'dev';
GRANT ALL PRIVILEGES ON DATABASE myapp TO app_user;
'';
};The initial script only runs when the data directory is first created. If you've already started PostgreSQL, delete the data directory to re-run it: rm -rf .stack/state/services/postgres/data/
Using with Drizzle
A common pattern is to pair PostgreSQL with Drizzle ORM. Stackpanel can generate the drizzle.config.ts for you:
{
stackpanel.globalServices.postgres.enable = true;
stackpanel.devshell.env.DATABASE_URL =
"postgresql://localhost:${toString config.stackpanel.ports.computed.postgres}/myapp";
stackpanel.scripts."db:migrate" = {
exec = "drizzle-kit migrate";
description = "Run database migrations";
};
stackpanel.scripts."db:studio" = {
exec = "drizzle-kit studio";
description = "Open Drizzle Studio";
};
stackpanel.scripts."db:seed" = {
path = ./.stack/src/scripts/db-seed.sh;
description = "Seed the database with test data";
};
}Connecting from External Tools
Because PostgreSQL runs on a stable, deterministic port, you can save connection profiles in tools like pgAdmin, TablePlus, or DataGrip and they'll always work:
- Host:
localhost - Port: Value of
$STACKPANEL_POSTGRES_PORT(check withstackpanel port postgres) - Database: Your project name (or custom
databasevalue) - User: Your system username (local peer auth, no password needed)
Troubleshooting
Port already in use
If you see a "port already in use" error, another process is occupying the deterministic port. Check what's using it:
lsof -i :$STACKPANEL_POSTGRES_PORTThis is rare since deterministic ports are project-specific, but it can happen if you have a system PostgreSQL running on a coincidentally matching port.
Database not created
If the auto-created database is missing, create it manually:
createdb myappOr reset the data directory to trigger a fresh initialization:
rm -rf .stack/state/services/postgres/data/
stackpanel services restart postgresPermission denied
Stackpanel runs PostgreSQL as your current user with local peer authentication. If you're seeing permission errors, ensure you're connecting without a password and with your system username.
Reference
- Options Reference → GlobalServices for all PostgreSQL options
- Deterministic Ports for how port assignment works
- Services Overview for the service lifecycle