When working with Docker volumes in docker-compose, many developers expect database files to appear in their mounted directory in the same format as they exist in the container. However, PostgreSQL (and many other databases) store data in specialized binary formats rather than human-readable SQL files.
version: "2"
services:
postgres:
image: postgres:9.6
volumes:
- ./vol_folder:/var/lib/postgresql
ports:
- "5432:5432"
The mounted volume ./vol_folder
does indeed contain your database data, but in PostgreSQL's native storage format. The empty data
directory you see is actually where PostgreSQL stores:
- Binary data files (.dat)
- Transaction logs
- Configuration files
- Index structures
To confirm your data is being persisted, try these commands:
# After running your test INSERTs
docker-compose down
docker-compose up
psql -h 192.168.99.100 -p 5432 -U postgres -c "SELECT * FROM test;"
If you see your test data, the volume is working correctly - just not in the SQL format you expected.
For guaranteed persistence even after container recreation, modify your compose file:
version: "3.8"
services:
postgres:
image: postgres:9.6
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
volumes:
postgres_data:
If data disappears after docker-compose down
, check:
- Volume mount permissions
- PostgreSQL user rights in container
- Whether you're using the exact same volume path
- Docker volume inspection commands:
docker volume ls docker volume inspect [VOLUME_NAME]
To get human-readable SQL dumps while keeping binary storage:
docker exec -t your_postgres_container pg_dumpall -U postgres > backup.sql
When you mount ./vol_folder:/var/lib/postgresql
in your docker-compose file, you're creating a bind mount that directly links the host directory to the container's PostgreSQL data directory. Here's what's actually happening:
version: "2"
services:
postgres:
image: postgres:9.6
volumes:
- ./vol_folder:/var/lib/postgresql # This is the critical line
ports:
- "5432:5432"
The empty data
directory you're seeing suggests PostgreSQL initialization hasn't properly occurred. The database files aren't in SQL format - they're binary files stored in PostgreSQL's native format. When the container starts for the first time:
- If the mounted directory is empty, PostgreSQL initializes a new database cluster
- If the directory contains existing data, PostgreSQL uses that data
Here's a more robust approach to ensure data persists between container restarts:
version: "3.8"
services:
postgres:
image: postgres:9.6
volumes:
- postgres_data:/var/lib/postgresql/data # Named volume for persistence
ports:
- "5432:5432"
environment:
- POSTGRES_PASSWORD=mysecretpassword
volumes:
postgres_data:
The actual storage location depends on your host OS:
macOS (Docker Desktop):
~/Library/Containers/com.docker.docker/Data/vms/0/
Linux:
/var/lib/docker/volumes/
Windows (Docker Desktop):
\\wsl$\docker-desktop-data\data\docker\volumes\
To inspect your volumes and their locations:
# List all volumes
docker volume ls
# Inspect a specific volume
docker volume inspect volume_name
# See the actual files in a volume
docker run -it --rm -v volume_name:/vol busybox ls -la /vol
For production databases, consider these recommendations:
- Always use named volumes for databases (better performance and management)
- Set appropriate volume permissions (PostgreSQL typically needs UID 999)
- Consider volume drivers for advanced storage needs
- Implement regular volume backups
# Example backup command
docker run --rm -v postgres_data:/source -v $(pwd):/backup busybox tar czf /backup/postgres_backup.tar.gz /source