I know, I know, PostgreSQL usually feels more at home on Linux. But guess what? PgHero works just fine on Windows too, and I gave it a try myself. If you’re running PostgreSQL in a Docker container, this setup is surprisingly easily, and it gives you a great performance dashboard without touching your base system.

In this post, I’ll show you how I set it up with Docker Compose, including running PgHero itself in a container. The goal: a fully contained stack that’s easy to spin up, monitor, and tear down anytime.

What you need

  • Docker Desktop installed on Windows (I recommend using WSL2 for smooth volume mounting).
  • A PostgreSQL database running in Docker. We’ll build the stack together if you don’t have one yet. In my case, I decided to install PgHero when I was following one of the NestJs course, and used my existing stack.
  • Basic familiarity with Docker Compose and command-line.

Optionally, you can create a folder on your PC to store database files, so your data sticks around even if the container stops. I will use a volume in this blog, to easily edit my PostgreSQL configuration.

Step 1: Your Docker Compose setup

Here’s a minimal Compose file for PostgreSQL, Redis, and PgHero. Save it somewhere on your machine, like C:\docker\pghero-setup\docker-compose.yml:

version: "3"
services:
  db:
    image: postgres
    restart: always
    ports:
      - "5438:5432"
    environment:
      POSTGRES_PASSWORD: pass123
      POSTGRES_USER: postgres
      POSTGRES_DB: postgres
    volumes:
      - "C:/Users/frj/Documents/Training/Nestjs/auth-extension/docker/postgres-data:/var/lib/postgresql/data"

  redis:
    image: redis
    ports:
      - "6379:6379"
    restart: always

  pghero:
    image: ankane/pghero
    depends_on:
      - db
    ports:
      - "8080:8080"
    environment:
DATABASE_URL: postgres://postgres:pass123@db:5432/postgres PGHERO_USERNAME: admin PGHERO_PASSWORD: secret restart: always

Why this works:

  • db is your PostgreSQL service. The bind mount points to a folder on your PC, so your data survives container restarts.
  • The command lines ensure PostgreSQL loads pg_stat_statements, which PgHero uses to track queries.
  • pghero runs in its own container and exposes port 8080 for the dashboard.
  • depends_on: db ensures PgHero waits for PostgreSQL to start.

Step 2: Monitoring multiple databases

To be able to track more than one database, we create a pghero.yml file instead of using the DATABASE_URL environment variable. Create the file in the same directory as docker-compose.yml:

databases:
  primary:
    url: postgres://postgres:pass123@db:5432/postgres
  analytics:
    url: postgres://postgres:pass123@db:5432/analytics

Then update docker-compose.yml for PgHero:

  pghero:
    image: ankane/pghero
    depends_on:
      - db
    ports:
      - "8080:8080"
    environment:
      PGHERO_USERNAME: admin
      PGHERO_PASSWORD: secret
    volumes:
      - "./pghero.yml:/app/config/pghero.yml:ro"
    restart: always

PgHero will now show a dropdown to switch between databases in the UI.

Step 3: Start everything

In the folder with your docker-compose.yml:

docker-compose down  # stop any previous run
docker-compose up -d

After a few seconds, open your browser at http://localhost:8080. Log in with the username and password you set (admin / secret). You should see the PgHero dashboard connected to your database.

Step 4: Enable query tracking

After starting PostgreSQL, connect to it and enable the pg_stat_statements extension. Inside your container, run:

docker exec -it <db_container> psql -U postgres -d postgres

Then in psql:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

This makes sure PgHero can track queries, see long-running statements, and show useful stats. Note that you have to do it for each database.

Step 5: Windows-specific tips

  • Use forward slashes (C:/path/to/folder) for volume paths in Compose.
  • Make sure the folder exists before starting PostgreSQL.
  • Check your pg_hba.conf if you see connection errors — Docker containers have their own internal IPs, and PostgreSQL needs to allow connections from them.

Step 6: Common troubleshooting

  • 500 Internal Server Error / cannot connect: Usually a problem with pg_hba.conf. Make sure your Docker network is allowed.
  • No stats showing: Ensure pg_stat_statements is loaded and the extension is created.
  • Dashboard not reachable: Check Docker mapped ports, firewall, and container logs (docker logs <container-id>).

Conclusion

And that’s it! You now have a Windows-based Docker setup with PostgreSQL and PgHero. You can see your query stats, monitor performance, and even track multiple databases from the same dashboard.