Overview
A local Postgres instance is the foundation for every backend tutorial on this site. This guide installs Postgres, creates a dedicated role and database, sets up password authentication, and verifies the connection. The production hardening checklist lives in postgres-prod; the query tuning workflow lives in debug-postgres-slow-query.
Prerequisites
- Ubuntu 22.04 / 24.04, macOS 14+, or Windows 11 with WSL2. The commands below target Debian-family Linux; macOS variants are noted inline.
sudoaccess. The Postgres service install requires it.- A terminal with
curlavailable.
Steps
1. Install Postgres
Ubuntu / Debian
sudo apt update
sudo apt install -y postgresql postgresql-contrib
sudo systemctl enable --now postgresqlmacOS (Homebrew)
brew install postgresql@16
brew services start postgresql@16
echo 'export PATH="/opt/homebrew/opt/postgresql@16/bin:$PATH"' >> ~/.zshrc
source ~/.zshrcVerify the process is running:
pg_isready
# /var/run/postgresql:5432 - accepting connections2. Create a role and database
Connect as the superuser, then create a non-superuser role for application use. Avoid running application code as postgres.
sudo -u postgres psqlInside psql:
CREATE ROLE myapp WITH LOGIN PASSWORD 'changeme' CREATEDB;
CREATE DATABASE myapp_dev OWNER myapp;
\qKeep the password out of shell history by using \password myapp instead of the inline form when security matters.
3. Configure pg_hba.conf for password auth
By default Ubuntu configures peer auth for local connections, which means the OS user must match the Postgres role. Switch to scram-sha-256 so any user can authenticate with a password.
Find the config file:
sudo -u postgres psql -c "SHOW hba_file;"
# /etc/postgresql/16/main/pg_hba.confEdit the file. Change the line for local from peer to scram-sha-256:
# TYPE DATABASE USER ADDRESS METHOD
local all all scram-sha-256
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
Reload the service for the change to take effect:
sudo systemctl reload postgresql4. Connect as the application role
psql -U myapp -d myapp_dev -h localhost
# Password for user myapp: changemeThe -h localhost flag forces a TCP connection, which uses host rules in pg_hba.conf. Without it you get a UNIX socket and hit the local rules.
5. Set a DATABASE_URL environment variable
Most frameworks and prisma read a single connection string:
export DATABASE_URL="postgresql://myapp:changeme@localhost:5432/myapp_dev"Add it to a .env file and gitignore it. Never commit credentials. See migrations for how Prisma and raw SQL migrations consume this variable.
Verify it worked
# 1. psql connects and shows the correct database.
psql "$DATABASE_URL" -c "SELECT current_user, current_database();"
# current_user | current_database
# --------------+-----------------
# myapp | myapp_dev
# 2. The role exists with the right privileges.
psql -U postgres -c "\du myapp"
# 3. The service restarts cleanly.
sudo systemctl restart postgresql && pg_isreadyCommon errors
FATAL: Peer authentication failed for user "myapp". You connected via UNIX socket. Add-h localhostto force TCP, or change thelocalrule inpg_hba.conftoscram-sha-256and reload.- **
pg_isreadyshows “no response”**. The service is not running. Runsudo systemctl status postgresqlto see the error; a missingdata/directory often meansinitdb` was not run. createdb: error: could not connect to database template1. The install did not runinitdb. On Ubuntu runsudo pg_createcluster 16 main --start.- Password prompt appears but correct password is rejected. The
pg_hba.confline usesmd5while the role was created withscram-sha-256. Align the method or recreate the role. - Port 5432 already in use. Another Postgres version is running.
sudo lsof -i :5432to find it; stop it or change the port inpostgresql.conf.