Short answer
Read the address and port in the error, then check something is running there: the database, Redis, your API or the dev server. If it is running, the host is wrong for where the code runs: inside Docker, localhost is the container itself, so use the service name from docker-compose (db:5432) or host.docker.internal. On Node.js 17 or 18, an error showing ::1 can mean localhost resolved to IPv6 while the server listens on IPv4 only: use 127.0.0.1 or make the server listen on both. On a host like Vercel, localhost never works: use the real database URL.
Why the connection is refused, and the fix
01
The service is not running
“This usually results from trying to connect to a service that is inactive on the foreign host.” Node.js, Errors: Common system errors
The most common case: the database, cache or API the app connects to was never started, crashed, or listens on a different port. Start it, and check the port it actually uses.
# is anything listening on 5432? lsof -nP -iTCP:5432 -sTCP:LISTEN # macOS / Linux # start it, for example with Docker docker compose up -d db02
localhost inside Docker points at the container
In a container, localhost and 127.0.0.1 mean the container itself, not your machine or the other containers. Use the compose service name as the host, or host.docker.internal to reach a service on your machine (on Linux, add it with extra_hosts). Two more container cases: the app can start before the database is ready, so wait for a healthcheck (below) or retry; and a server inside a container that binds to 127.0.0.1 can’t be reached through a published port, so bind it to 0.0.0.0.
# docker-compose.yml services: api: environment: DATABASE_URL: postgres://app:secret@db:5432/app depends_on: db: condition: service_healthy db: image: postgres:16 environment: POSTGRES_USER: app POSTGRES_PASSWORD: secret POSTGRES_DB: app healthcheck: test: ["CMD-SHELL", "pg_isready -U app"] interval: 2s retries: 1503
::1 versus 127.0.0.1 (Node.js 17 and 18)
“v17.0.0 Changed default value to verbatim.” Node.js, DNS: dns.setDefaultResultOrder()
Since Node.js 17, localhost is resolved in the order the system returns, so it can resolve to the IPv6 address ::1 first. On Node.js 17 and 18, a server that only listens on IPv4 refuses that connection. Node.js 20 and later try the next address automatically, so there an error that lists both ::1 and 127.0.0.1 (AggregateError) means nothing is listening on that port at all. Either way, use 127.0.0.1 in the connection string, or make the server listen on both families.
04
Production still points at localhost
A connection string copied from .env.local into production points at a database that only existed on your laptop. On Vercel, Netlify or a container host, set the real host in the environment variables, and make sure the database allows connections from that host.
Checked against the vendor’s docs on : Node.js: Errors: Common system errors (ECONNREFUSED); Node.js: DNS (result order, IPv4 and IPv6).
Rather hand it over?
Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.
- from $450App Fix TicketOne reproducible bug in an existing mobile or web app, diagnosed and fixed.See scope and start
- from $450AI-Built App RescueA Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.See scope and start
Related: Node.js EADDRINUSE: address already in use · Prisma “Can’t reach database server” · “Uncaught (in promise)”