How to initialize a PSQL database in docker-compose file?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
The easiest way to initialize PostgreSQL in Docker Compose is to use the official postgres image and mount SQL or shell files into /docker-entrypoint-initdb.d. On first startup, the container creates the database directory, creates the configured database and user, and runs those initialization files in order.
The detail that trips people up is "first startup." If your data volume already contains a database cluster, the init scripts will not run again, so repeated edits to init.sql appear to do nothing.
Basic Compose Setup
A minimal docker-compose.yml can define the database, credentials, port mapping, and a persistent volume:
When the container starts with an empty data directory, PostgreSQL creates app_db and then executes init.sql.
Add Seed SQL
Your initialization file can create tables, indexes, and seed data:
Bring the service up with:
The logs are the quickest way to confirm that the entrypoint detected an empty database and executed the script.
Initialize with Multiple Files
You are not limited to one SQL file. The image executes files in lexical order, so a directory mount is convenient for larger setups:
An example directory could look like this:
Shell scripts are also supported, which is useful if you need conditional logic or additional psql commands.
Re-Running Initialization During Development
Because init scripts only run against an empty data directory, local development often requires resetting the volume:
That removes the named volume and forces PostgreSQL to initialize from scratch. Do not use this in environments where you care about preserving data.
If you need repeatable schema changes after the database already exists, use a migration tool such as Flyway, Liquibase, Alembic, or your framework's built-in migration system. Init scripts are for bootstrap, not ongoing schema evolution.
Verify the Database
You can connect from the host or from inside the container:
Or:
Then confirm the seeded table exists:
Common Pitfalls
- Editing
init.sqland expecting changes to apply to an existing volume. The entrypoint skips init scripts once data already exists. - Forgetting to mount scripts into
/docker-entrypoint-initdb.d, which means the container starts normally but nothing is seeded. - Using production credentials directly in the Compose file. Prefer environment files or secrets for real deployments.
- Relying on init scripts for schema upgrades. Use migrations once the database is no longer disposable.
- Mounting a Windows-formatted script with line-ending issues can break shell-based init scripts. SQL files are usually less sensitive, but shell files should use Unix line endings.
Summary
- Use the official
postgresimage withPOSTGRES_USER,POSTGRES_PASSWORD, andPOSTGRES_DB. - Mount SQL or shell files into
/docker-entrypoint-initdb.d. - Initialization runs only when the database directory is empty.
- Reset the volume during development if you need bootstrap scripts to run again.
- Use a migration tool for changes after the first initialization.

