Disc downloads and manages PostgreSQL automatically. Users never install, configure, or manage PostgreSQL directly. Running disc init triggers the download of a platform-specific PostgreSQL binary, initializes a data directory, and creates a fully managed instance. The bundled PostgreSQL is ready to use immediately with no external dependencies.
When you run disc init, the following happens:
darwin-arm64, darwin-x64, linux-x64, linux-arm64, windows-x64).~/.disc/postgres/<version>/. If the binary is already cached, the download is skipped.bin/, lib/, and share/ are directly under the version directory.initdb creates a new PostgreSQL data directory with UTF-8 encoding, the disc superuser, and trust-based local authentication.postgresql.conf is written with settings tuned for Disc: Unix socket only, no TCP listener, logging collector enabled, and conservative memory defaults.Subsequent runs of disc start reuse the cached binary and existing data directory without repeating the download or initialization steps.
All Disc-managed PostgreSQL data lives under ~/.disc/:
~/.disc/
instances/
my-project/
data/ # PostgreSQL data directory (PGDATA)
logs/ # PostgreSQL and Disc server logs
socket/ # Unix domain socket directory
disc.toml # Instance configuration
postgres/
18.4/ # Cached PostgreSQL 18.4 binary
bin/ # postgres, initdb, pg_ctl, psql, etc.
lib/ # Shared libraries
share/ # Extensions, timezone data, configs
17.0/ # Multiple versions can coexist
bin/
lib/
share/
Each project gets its own instance directory under ~/.disc/instances/. Data directories, logs, and Unix sockets are isolated per project. PostgreSQL binaries are shared across all instances of the same version.
| Platform | Architecture | Source |
|---|---|---|
| macOS | arm64 | Zonky embedded-postgres-binaries |
| macOS | x64 | Zonky embedded-postgres-binaries |
| Linux | x64 | Zonky embedded-postgres-binaries |
| Linux | arm64 | Zonky embedded-postgres-binaries |
| Windows | x64 | Zonky embedded-postgres-binaries |
All platforms are sourced from Zonky’s embedded-postgres-binaries artifacts on Maven Central — one JAR per platform, each wrapping a postgres-<platform>.txz. On Windows, the download source is the same, but the bundled-PostgreSQL runtime lifecycle is not yet validated; --backend-dsn (external PostgreSQL) is the supported path on Windows for now.
Supported PostgreSQL versions: 16.4, 17.0, 18.4 (default).
The platform is detected automatically from Deno.build.os and Deno.build.arch. If Disc does not recognize your platform, it will report an error with the detected OS and architecture.
Start the bundled PostgreSQL and the Disc server together:
disc start
This starts PostgreSQL via pg_ctl start, waits up to 60 seconds for the process to become ready, and then launches the Disc HTTP server. If PostgreSQL is already running, it is not restarted.
Most commands (serve, migrate, shell, start) auto-start PostgreSQL when needed. You rarely need to run disc start explicitly -- just disc serve or disc shell from any subdirectory of your project and the CLI will locate disc.toml, resolve the instance, and start PostgreSQL if it is not already running.
Stop the Disc server and PostgreSQL:
disc stop
PostgreSQL is stopped with pg_ctl stop -m fast, which rolls back any in-progress transactions and shuts down cleanly. If a clean shutdown fails, Disc sends SIGTERM and waits 5 seconds. If the process is still alive, SIGKILL is used as a last resort.
Check whether the server and PostgreSQL are running:
disc status
This reports the running state, PID, data directory, socket path, port, PostgreSQL version, and health monitor status.
Restart PostgreSQL without restarting the full Disc server:
disc stop && disc start
The PostgresInstance.restart() method performs a stop followed by a start internally.
View PostgreSQL logs:
disc pg log
Follow log output in real time:
disc pg log --follow
Show only the last 50 lines:
disc pg log --lines 50
Filter by log level:
disc pg log --level error
Logs are stored at ~/.disc/instances/<name>/logs/postgresql.log. The logging collector is enabled by default with daily rotation and a 100 MB size limit. Log files follow the naming pattern postgresql-YYYY-MM-DD_HHMMSS.log.
The log line prefix includes the timestamp, process ID, user, and database:
2026-03-20 14:30:15 UTC [12345] disc@my-project LOG: statement: SELECT 1
Slow queries exceeding 100 ms are logged automatically via log_min_duration_statement.
Upgrade the bundled PostgreSQL to a newer version:
disc pg upgrade --target-version 17
Preview what would happen without making changes:
disc pg upgrade --target-version 17 --dry-run
The upgrade process:
The old PostgreSQL binary remains cached at ~/.disc/postgres/<old-version>/ and is not deleted, so rollback is always possible.
Status: the full
pg_dump/pg_restoreupgrade pipeline isn’t implemented yet —upgradeInstancecurrently throws an error indicating the feature is in development. The CLI surface and the flow described above are the intended behavior. The command is gated until the pipeline ships, so running it on a real instance is safe (it errors out before touching anything).
Disc generates a postgresql.conf tuned for local development. The configuration is written to the data directory during disc init and can be edited manually afterward.
Default settings:
# Connection Settings
listen_addresses = "" # Unix socket only, no TCP
max_connections = 100
port = 5432 # Port for socket file naming
superuser_reserved_connections = 3
# Memory Settings
effective_cache_size = 512MB
maintenance_work_mem = 64MB
shared_buffers = 128MB
work_mem = 4MB
# WAL Settings
checkpoint_completion_target = 0.9
max_wal_size = 1GB
min_wal_size = 80MB
wal_level = replica
# Query Tuning
default_statistics_target = 100
random_page_cost = 1.1
# Logging
log_min_duration_statement = 100
log_rotation_age = 1d
log_rotation_size = 100MB
log_statement = "all"
logging_collector = on
# Disc-specific
jit = off # Disabled for predictable performance
timezone = "UTC"
Disc can auto-tune memory settings based on available system memory:
import { PostgresConfig } from "disc/postgres/mod.ts";
const config = new PostgresConfig();
const tuned = config.tuneForMemory(4096); // 4 GB of RAM
// {
// maxConnections: 100,
// sharedBuffers: "1024MB",
// workMem: "40MB"
// }
For systems with less than 1 GB of RAM, maxConnections is automatically reduced to 50.
Adjust the connection limit in disc.toml or by editing postgresql.conf directly:
max_connections = 200
Three connections are always reserved for superuser access (superuser_reserved_connections = 3).
By default, PostgreSQL listens only on a Unix domain socket. The socket file is created at:
~/.disc/instances/<name>/socket/.s.PGSQL.5432
The connection DSN for socket-based connections:
postgresql://disc@/<instance-name>?host=/path/to/socket
No TCP port is exposed unless you explicitly set a port:
const instance = new PostgresInstance({
dataDir: "/path/to/data",
instanceName: "my-project",
port: 5433 // Enable TCP on this port
});
When a non-zero port is set, PostgreSQL listens on both the TCP port and the Unix socket.
For production deployments or environments where you manage your own PostgreSQL, use the --backend-dsn escape hatch:
disc init my-app --backend-dsn "postgres://user:pass@host:5432/disc"
When --backend-dsn is provided:
disc_migrations, disc_schema, etc.) within the target database.You can also point to an existing PostgreSQL binary directory instead of downloading:
const instance = new PostgresInstance({
dataDir: "/path/to/data",
instanceName: "my-project",
pgBinDir: "/usr/local/pgsql/bin" // Use existing PG binaries
});
When pgBinDir is set, the download step is skipped and Disc uses the binaries at the specified path.
?sslmode=...)When connecting to an external PostgreSQL over TCP, append ?sslmode=<mode> to the DSN. Disc parses the parameter out of the connection string and forwards a matching tls option to the underlying driver:
sslmode |
TLS enabled | Enforced (refuse plain) | Notes |
|---|---|---|---|
disable |
no | n/a | Plaintext only. |
prefer |
yes | no | Try TLS, fall back to plain if unavailable. |
require |
yes | yes | Refuse the connection if TLS is unavailable. |
verify-ca |
yes | yes | Same enforcement as require. CA verification beyond the driver default is not yet wired. |
verify-full |
yes | yes | Same enforcement as require. Hostname verification is not yet wired. |
disc init my-app --backend-dsn "postgres://user:pass@db.example.com:5432/disc?sslmode=require"
Unix-socket DSNs ignore sslmode — sockets don’t carry TLS. Unknown values are dropped at parse time so a typo never silently downgrades a require connection to plaintext. (lib/database.ts:parseConnectionString, gh/geldata#2292)
The PostgresMonitor runs periodic health checks against the PostgreSQL instance.
When a health check fails (connection refused, query timeout, or process not running):
pg_ctl stop followed by pg_ctl start.PostgreSQL failed after 3 restart attempts. Manual intervention required.
import { PostgresMonitor } from "disc/postgres/mod.ts";
const monitor = new PostgresMonitor(instance, {
autoRestart: true, // Enable auto-restart (default: true)
checkIntervalMs: 15000, // Check every 15 seconds
maxRestartAttempts: 5, // Allow 5 restart attempts before giving up
restartDelayMs: 10000 // Wait 10 seconds between restart attempts
});
await monitor.start();
Query the current health status programmatically:
const health = await monitor.checkHealth();
// {
// connections: 3,
// healthy: true,
// lastCheck: 2026-03-20T14:30:00.000Z,
// latencyMs: 5,
// uptime: 86400,
// version: "PostgreSQL 18.4 on ..."
// }
monitor.isHealthy(); // true
The monitor can also collect detailed database metrics:
const metrics = await monitor.getMetrics();
// {
// connections: { active: 2, idle: 5, total: 7 },
// database: { size: "42 MB" },
// tables: { count: 12, totalSize: "38 MB" }
// }
Run ANALYZE and VACUUM on all tables:
await monitor.performMaintenance();
This updates table statistics and reclaims storage from dead rows. It is safe to run during normal operation but may cause a brief increase in I/O.
Disc supports multiple project instances running simultaneously. Each instance has its own data directory, log directory, and Unix socket:
disc init project-a
disc init project-b
The PostgresManager tracks all known instances:
import { PostgresManager } from "disc/postgres/mod.ts";
const manager = new PostgresManager();
// Discover instances from disk
await manager.discoverInstances();
// List all known instances
manager.listInstances(); // ["project-a", "project-b"]
// Start a specific instance
await manager.startInstance("project-a");
// Get status for a specific instance
const status = await manager.getInstanceStatus("project-a");
Instances are independent. Starting, stopping, or destroying one instance does not affect others.
Back up an instance to a tar.gz archive:
await manager.backupInstance("my-project", "/backups/my-project.tar.gz");
The backup process stops PostgreSQL for a consistent snapshot, creates the archive, and restarts PostgreSQL. If the instance was not running before the backup, it remains stopped afterward.
Restore from a backup:
await manager.restoreInstance("restored-project", "/backups/my-project.tar.gz");
This creates a new instance with the restored data. The instance name must not already exist.
Remove an instance from the manager without deleting data:
await manager.destroyInstance("my-project");
Remove an instance and delete all data:
await manager.destroyInstance("my-project", true);
PostgreSQL listens exclusively on a Unix domain socket. No TCP port is exposed unless explicitly configured. This means:
Local connections use trust authentication by default, which is appropriate for development. The pg_hba.conf generated by Disc allows:
127.0.0.1/32 (localhost only).::1/128 (localhost only).For production use with an external PostgreSQL, configure your server’s pg_hba.conf with appropriate authentication methods (e.g., scram-sha-256).
All PostgreSQL binary downloads are verified against SHA-256 checksums before extraction. If a checksum does not match, the download is rejected and the archive is deleted. This prevents tampered binaries from being installed.
Extracted PostgreSQL binaries are set to mode 0755 (owner read/write/execute, group and others read/execute). The data directory is owned by the current user and is not world-readable by default.
| Command | Description |
|---|---|
disc start |
Start bundled PostgreSQL and the Disc server |
disc stop |
Stop the Disc server and bundled PostgreSQL |
disc status |
Show instance status (running, PID, port, data dir) |
disc pg log |
View PostgreSQL logs |
disc pg log --follow |
Tail PostgreSQL logs in real time |
disc pg log --lines 50 |
Show last 50 log lines |
disc pg log --level error |
Filter logs by severity level |
disc pg upgrade --target-version 17 |
Upgrade PostgreSQL to version 17 |
disc pg upgrade --target-version 17 --dry-run |
Preview upgrade without making changes |
disc init --backend-dsn <url> |
Use an external PostgreSQL instead of bundled |
Check the logs first:
disc pg log --lines 20
Common causes:
postmaster.pid file may remain. Disc detects and cleans up stale PID files automatically.disc init.After 3 consecutive failed restart attempts, the monitor stops and logs:
PostgreSQL failed after 3 restart attempts. Manual intervention required.
Investigate the cause in the PostgreSQL logs, fix the issue, and restart manually:
disc stop && disc start
If the download URL is unreachable or the checksum does not match, Disc reports the error and exits. Check your network connection and try again. The cached binary at ~/.disc/postgres/<version>/ can be deleted to force a fresh download:
rm -rf ~/.disc/postgres/18.4
disc start