Prisma: Can't reach database server at database:5432 on M1
Check the address seen by the app container, preserve the PostgreSQL volume and distinguish a reachable database from a healthy container.
TL;DR#
Prisma's P1001 means it cannot reach the database server named in the error. An M1 Mac does not establish the cause. From an app container, use the PostgreSQL service name and container port, ensure the services share a network, then check readiness. Keep the database volume. A longer connection timeout is useful only after the address and route are correct.
The original M1 question reports:
Can't reach database server at `test-postgres`:`5432`Its accepted answer adds a connection timeout; other answers report different results after changing Node versions. Those observations do not prove an ARM-specific DNS defect, a universal startup race or automatic Prisma retries. This page's network controls were reproduced in Linux Docker containers on 4 November 2026, not on an Apple Silicon host and not as a reproduction of that person's machine.
Why it happens#
Start with the Prisma error reference. P1001 is the unreachable-server error; P1002 separately describes a server that was reached but timed out. Neither code alone tells you that the database volume is damaged or that a different Node major will repair it.
There are separate questions to answer: can the application resolve its configured hostname, can it open the configured port, and can the database accept the intended connection? A container shown as running in Docker Desktop answers none of those from the application's network context. Even a successful local readiness check inside the database container does not prove that another container can reach it.
The original material also includes a missing _prisma_migrations relation in PostgreSQL logs. A database reporting a SQL relation error has received a query. That message does not prove that every client failed its initial connection, and it should be investigated separately from an unreachable-server message.
Fix#
1. Inspect the address the app actually receives#
For a service called next, inspect only the non-secret URL fields rather than printing the password:
docker compose exec next node -e 'const u = new URL(process.env.DATABASE_URL); console.log({host: u.hostname, port: u.port, database: u.pathname});'This assumes the application reads DATABASE_URL; inspect the equivalent configuration input if it does not. An environment value supplied by Compose can differ from the text in an application environment file. Diagnose the value the failing process uses.
In the example below, the database service is postgres. Its container port is 5432. If the application runs in the sibling container, the address is postgres:5432. If it runs directly on your Mac and you publish a host port, use that host mapping instead. Docker's Compose networking guide explains this distinction.
localhost inside the app container refers to that container itself. Increasing a timeout cannot turn it into the PostgreSQL container. The Postgres ECONNREFUSED checklist covers this address mistake with a Node application.
2. Check that both services share a network#
Compose normally joins services to one default network, where their service names are discoverable. Explicit network declarations change that arrangement. A database attached only to a custom network and an app attached only to the default network do not acquire shared service discovery merely because they appear in the same YAML file.
Identify the containers and compare their network names:
docker compose ps
docker inspect --format '{{json .NetworkSettings.Networks}}' YOUR_APP_CONTAINER
docker inspect --format '{{json .NetworkSettings.Networks}}' YOUR_DATABASE_CONTAINERReplace the two container names with those listed by the first command. Inspecting these network fields does not dump environment credentials. Fix membership in the Compose file, rather than hard-coding the changing container IP address.
The supplementary control used an already-ready PostgreSQL container on one network and a Node container on another. The Node TCP probe timed out before it could connect. Attaching the database to the app's network with that alias was the only change before the same probe succeeded. PostgreSQL was ready before both attempts. This proves that readiness alone does not repair separate networks; it does not establish the historical question's cause.
3. Add a readiness dependency without resetting data#
For an existing app whose Dockerfile is in the current directory, this complete Compose example uses the default network and a declared data volume:
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_PASSWORD: local-development-only
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d app"]
interval: 5s
timeout: 5s
retries: 10
next:
build: .
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgresql://postgres:local-development-only@postgres:5432/app
volumes:
pgdata:The credentials are for a disposable local example. Keep your project's existing credentials, data volume and database image when repairing an established stack; changing a database major is a separate migration. The example adds no published database port because sibling services communicate over the Compose network.
Docker's startup-order documentation states that a service_healthy dependency waits for the configured healthcheck before starting the dependent service. This addresses initial ordering. It is not a guarantee against later database outages, bad credentials or an application that uses a different URL.
Validate the file and recreate changed services:
docker compose config --quiet
docker compose up -d --buildDo not add down -v as a clean-slate step. The Compose down reference documents that this option removes declared named volumes and attached anonymous volumes. Here that includes pgdata, containing the database. The network reproduction also checked that a row remained after a normal database-container restart.
Check your own connection string#
Use the connection-string doctor to inspect the URL's hostname, port and encoding. It runs in your browser; nothing is sent. A URL inspection cannot test whether the services share a Docker network.
Runs entirely in your browser — nothing you paste is sent anywhere, and the password is masked in every result. Still cautious? Replace the password with any string containing the same special characters: the diagnosis only needs its shape.
What connect_timeout changes#
For the built-in connector, Prisma's PostgreSQL connection arguments define connect_timeout as the timeout for opening a connection, in seconds. The historical answer's value is 300 seconds. It is an observation from that thread, not a universal setting to copy or a promise that refused connections will be retried until a database starts.
If this is the connector your project uses and a measured connection delay justifies changing the timeout, append the parameter with ? when the URL has no query string, or & when one already exists. Keep the hostname and network diagnosis separate. A JavaScript driver adapter delegates connection behaviour to its driver; use that driver's documented settings rather than assuming a URL parameter controls it.
Changing to an unsupported Node release is not a current fix. The Node release table marks the Node versions suggested in the old answers as end of life. Use a supported release compatible with the application and Prisma, without attributing an unproven ARM networking fix to it.
Verify the fix#
Check database readiness inside its service:
docker compose exec postgres pg_isready -U postgres -d appThen test the actual application operation from the app service. Use your project's existing non-destructive connection or read-query check before running schema migrations. A local pg_isready result is useful, but the app's successful connection is the relevant end-to-end result.
If the same problem appears in CI, check whether the job runs on the host runner or inside a job container: the GitHub Actions service-container example shows why those contexts use different addresses. If the message changes to a missing Prisma query-engine library, continue with the platform-library diagnosis; that is a different failure from an unreachable database.
Preserve the database, verify the address from the failing process and change one condition at a time. A successful app query after the network or readiness repair is evidence of that repair; the Mac's processor name alone is not a diagnosis.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Prisma Migrate P3014: permission denied to create database
Hit `P3014: permission denied to create database` when running Prisma Migrate on Heroku Postgres? Use prisma db push, a separate shadow database, or grant CREATEDB — and fix hangs with Supabase pooled connections.
Prisma Can't Connect to PostgreSQL: Fix invalid port
Prisma error "invalid port number" often means your password contains characters like @ or # that break URL parsing. This guide shows how to percent-encode them and confirm the fix.
Fix Prisma 'Unique constraint failed on the fields: (id)'
Prove in two queries that the id sequence is stuck behind your imported rows, reset it safely even on an empty table, and see why retrying seems to fix it.


