Error: cannot connect to Postgres. Details: "connect ECONNREFUSED 127.0.0.1:5432"

Hello, I am new to Docker and web app dev in general.

Trying to run Payload & Postgres for a backend website and a db. Served as docker containers.

I have got as far as a successful build with both containers running, however Payload cannot connect to the database :frowning: might be a simple config error but I can’t figure it out

it gives this error:

[08:48:51] ERROR: Error: cannot connect to Postgres. Details:
{
          "type": "Error",
          "message": "connect ECONNREFUSED 127.0.0.1:5432",
          "stack":
              Error: connect ECONNREFUSED 127.0.0.1:5432
                  at createConnectionError (node:net:1652:14)
                  at afterConnectMultiple (node:net:1682:16)
                  at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17)
          "errno": -111,
          "code": "ECONNREFUSED",
          "syscall": "connect",
          "address": "127.0.0.1",
          "port": 5432
        }

build command I am using: docker compose up --build -d

My docker-compose.yml file:

version: '3.8'

services:
  payload_app:
    build:
      context: .
      dockerfile: ecommerce/Dockerfile
    ports:
      - "3000:3000"
    environment:
      PAYLOAD_SECRET: ${PAYLOAD_SECRET}
      DATABASE_URI: ${DATABASE_URI}
      NEXT_PUBLIC_SERVER_URL: http://localhost:3000
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      # CRITICAL FIX: Mount the 'ecommerce' subdirectory (your app's root) to /app
      - ./ecommerce:/app
      # This masks the host's node_modules within the mounted /app
      # It ensures node_modules created by pnpm install in the container persist
      - /app/node_modules
    command: sh -c "corepack enable && corepack prepare pnpm@latest --activate && pnpm install && pnpm dev"

  # PostgreSQL Database Service (unchanged)
  postgres:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_USER: root
      POSTGRES_PASSWORD: q5hL3RhxhwSITxP
      POSTGRES_DB: ecom_db
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U root -d ecom_db"] # Ensure this matches your POSTGRES_USER
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  pgdata:

My .env file:

COMPANY_NAME="Payload Inc."
TWITTER_CREATOR="@payloadcms"
TWITTER_SITE="https://nextjs.org/commerce"
SITE_NAME="Payload Commerce"

PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000
NEXT_PUBLIC_SERVER_URL=http://localhost:3000
# DATABASE_URI - Configure for PostgreSQL running in Docker
# The 'postgres' in the hostname refers to the service name in docker-compose.yml
DATABASE_URI=postgresql://root:q5hL3RhxhwSITxP@postgres:5432/ecom_db
DOCKER_BUILDKIT=1
PAYLOAD_SECRET=GTpcaShs2geGyHbLE4TErDhNJhYAuSAzMQFr1THv342

# Used to preview drafts
PAYLOAD_PUBLIC_DRAFT_SECRET=demo-draft-secret
NEXT_PRIVATE_DRAFT_SECRET=demo-draft-secret

# Used to revalidate static pages
REVALIDATION_KEY=demo-revalation-key
NEXT_PRIVATE_REVALIDATION_KEY=demo-revalation-key

# Stripe API keys
NEXT_PUBLIC_STRIPE_IS_TEST_KEY=true
STRIPE_SECRET_KEY=sk_test_
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_
STRIPE_WEBHOOKS_SIGNING_SECRET=whsec_

My payload.config.ts:

  // database-adapter-config-start
  db: postgresAdapter({
    url: process.env.DATABASE_URI,
  }),
  // database-adapter-config-end

UPDATE:

With a little (a lot, actually) help from AI it found this in the payload config file:

db: postgresAdapter({
  url: process.env.DATABASE_URI,
}),

needed to be wrapped in a pool object:

db: postgresAdapter({
  pool: {
    connectionString: process.env.DATABASE_URI,
  },
}),

it works fine now. No idea why

Is this what you are using?

https://authjs.dev/getting-started/adapters/pg#configuration

According to this documentation, postgresAdapter accepts a Pool object and I don’t see any parameter like “url”, only connectionString. So the answer is probably in how the library works, but I’m just guessing.

I also guess that the function uses localhost if the correct paameter is not passed. And localhost will always point back to the same container (without host network mode) in which you refer to localhost.