Use Docker Compose to define your web app and its dependencies once, then apply staging-specific settings with a profile or an override file. For repeatable web tests, start the stack under a unique project name, wait for dependencies to become ready, run the suite, and remove the stack afterward. Staging can run locally for CI and development, or on a secured remote Docker host when teammates need a shared preview URL.
What a Docker staging environment should do
A useful staging environment should be repeatable, close enough to the target deployment to reveal integration problems, and isolated from production data and credentials. Docker Compose models an application and its dependent services in one configuration, and Docker Docs says, “Compose works in all environments – production, staging, development, testing, as well as CI workflows.” See Docker Compose.
Start with a project directory containing your application’s Dockerfile and a compose.yaml. Define the web application as a service and add dependencies such as a database, cache, or queue as separate services. Containers on the Compose network can find each other by service name, so application configuration should refer to a database host such as db, not a container IP address that may change.
Choose how staging differs from development
You do not have to maintain a full, separate Compose file for every environment. Docker Docs’ “Common challenges and questions” notes that teams do not necessarily need entirely separate files for development, testing, and staging. Choose between profiles and merged files based on whether staging adds optional services or changes the configuration of existing ones.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errors#1 Best Overall
| Approach | Best fit | How to inspect it |
|---|---|---|
| Profiles in one Compose file | Environment-specific groups of optional services, such as a staging-only dashboard or mail catcher. | Run docker compose --profile staging config to inspect the resolved configuration. |
| Base file plus staging override | Changes to existing service settings, such as ports, environment, logging, or restart policy, while retaining shared services. | Run docker compose -f compose.yaml -f compose.staging.yaml config. |
Profiles are convenient for switching groups of services on and off. Overrides make changes to a shared base explicit in a separate file, which can make environment differences easier to review. Compose applies files in the order listed: later files override or add settings. Relative paths in merged files are resolved from the first Compose file, so account for that if an override sits in a subdirectory. See Docker Docs on profiles and merging Compose files.
Build the shared application stack
For a simple app with a database, the base file can define the common services and their network relationship. Adapt the image, build context, ports, and health-check command to your actual application and database.
services:
web:
build: .
depends_on:
db:
condition: service_healthy
environment:
DATABASE_HOST: db
DATABASE_NAME: app
DATABASE_USER: app
DATABASE_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
db:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 10
secrets:
db_password:
file: ./secrets/db_password.txt
This is an illustrative configuration, not a complete production secrets-management design: provision the secret file through your team’s secure process, exclude it from version control, and verify that the application reads its configured secret path. Compose secret support and the application’s expectations should be checked against the current Docker and app documentation. Docker warns against passing sensitive information such as passwords through ordinary environment variables and recommends secrets instead; see Docker Compose secrets.
The example uses PostgreSQL 16 as an explicit image tag; select and pin the version your application supports. Add a cache, queue, or other dependency as its own service when the tests need it, and configure the web service using that service’s Compose name.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Rank #2
Apply staging-specific settings
Using an override file
Create compose.staging.yaml with only the differences that belong in staging. For example, publish the app on a host port and remove any development bind mount that would let host files replace the code baked into the image:
services:
web:
ports:
- "8080:8080"
restart: unless-stopped
# Do not add the development bind mount here.
Start and inspect the merged setup with:
docker compose -f compose.yaml -f compose.staging.yaml config
docker compose -f compose.yaml -f compose.staging.yaml up -d
docker compose -f compose.yaml -f compose.staging.yaml ps
docker compose -f compose.yaml -f compose.staging.yaml logs -f
Docker’s production guidance recommends removing application-code bind mounts so the deployed code remains in the image, and adjusting ports and environment settings. Apply that production-like principle to staging when deployment fidelity matters; keep development conveniences in the development configuration instead. See Docker Compose in production.
Using a profile
Put an optional service under a staging profile in the shared file:
services:
diagnostics:
image: example/diagnostics:latest
profiles: ["staging"]
Enable it when starting the stack with docker compose --profile staging up -d. A profile is most helpful when selecting optional services; use an override when you need to change settings on the core web or dependency services.
Recommended Free Tools
Rank #3
Start, inspect, and verify the environment
- Validate the effective configuration. Run
docker compose -f compose.yaml -f compose.staging.yaml config, or use the profile variant if applicable. This catches malformed YAML and lets you review the settings Compose will apply. - Start the stack. Run
docker compose -f compose.yaml -f compose.staging.yaml up -d. Omit-dwhen you want logs in the foreground. - Check service state. Run
docker compose -f compose.yaml -f compose.staging.yaml ps. A running container is not necessarily an application-ready service; check health status where configured. - Inspect startup output. Run
docker compose -f compose.yaml -f compose.staging.yaml logs -f, optionally adding a service name such aswebordb. - Run an in-container check. Use
docker compose -f compose.yaml -f compose.staging.yaml exec web shto open a shell in the running web service, then run an application-specific health or connectivity check.
Docker’s Compose quickstart documents these start, inspect, and debug commands.
Make dependency readiness explicit
depends_on can control startup order, but order alone does not mean that a database or other dependency is ready to accept connections. Use a health check and, where supported, a dependency condition such as condition: service_healthy. The application should also handle transient connection failures appropriately rather than assuming the first connection will always succeed. Docker explains the distinction in its startup order guidance.
Health checks need to test a meaningful readiness condition. For example, pg_isready checks PostgreSQL readiness; a web service may need its own endpoint check. A container marked healthy does not prove that the whole application behaves correctly, so run the actual test suite as well.
Isolate parallel branches and CI jobs
Compose project names namespace resources such as containers and networks. Give every simultaneous branch or CI run a distinct name to avoid collisions:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
docker compose -p "webtest-${CI_JOB_ID}" up -d
For a local run, use a predictable unique name, for example docker compose -p webtest-feature-search up -d. Set COMPOSE_PROJECT_NAME instead if your automation passes it through the environment. Ensure the name is reused for test execution and teardown. Docker documents project names for isolating environments and running per-branch or uniquely named CI copies: project names.
Run tests and tear down the stack
A repeatable local or CI run creates a fresh isolated stack, waits for the required services, runs tests against the web app, and removes that stack even if tests fail. The test command is specific to your framework; the example below assumes the project has a test runner available in the web container:
PROJECT="webtest-${CI_JOB_ID:-local}"
cleanup() {
docker compose -p "$PROJECT" down
}
trap cleanup EXIT
docker compose -p "$PROJECT" up -d --build
# Wait for readiness using your health checks or a project-specific probe.
docker compose -p "$PROJECT" exec -T web npm test
Replace npm test with the real suite command. If tests run in a separate runner container or from the CI host, configure that runner to reach the app through the published port or Compose network as appropriate. Docker describes Compose as a way to create and destroy isolated environments for testing; see Use Compose for testing.
For a manually managed stack, stop and remove its containers and networks with docker compose -p webtest-feature-search down. Add --volumes only if you intentionally want to remove the Compose-managed data volumes too; doing so erases persisted database data for that project.
Best Value
- Docker, Docker Swarm, Docker Compose, Programmer, Developer, Coding, Programming, Software Engineer, Code, DevOps, Deploy, Deployment, Kubernetes, Salt, Puppet, Chef, Terraform, Container, AWS, Azure, Cloud, Geek, Funny, Computer, Software, Tech, IT
- Integration, Scrum, Compile, Compilation, Science, Bug, Debug, Python, Linux, Java, Javascript, Scala, Dotnet, Kotlin
- Lightweight, Classic fit, Double-needle sleeve and bottom hem
Choose local or shared remote staging
| Where it runs | Access | Ownership and exposure |
|---|---|---|
| Local Docker host | Best suited to one developer’s checks or CI jobs that create temporary environments. | Keep the stack scoped to the host and use unique project names for concurrent runs. |
| Remote Docker host | Can make a staging deployment reachable to teammates or testers, subject to the host’s network setup. | The team must manage remote access, credentials, and network exposure. Docker documents remote-host configuration, but does not prescribe a provider or universal access-control design. |
Docker documents remote daemon connections using settings including DOCKER_HOST, DOCKER_TLS_VERIFY, and DOCKER_CERT_PATH. Configure those values with the connection details for your secured host and protect the associated credentials; see Protect access to the Docker daemon socket. The appropriate network architecture and access policy depend on your application and organization.
Common failures and fixes
- The web service starts before the database accepts connections. Add a database health check and a readiness condition to
depends_on; make the app tolerate transient connection failures. - The app cannot resolve its database host. Use the Compose service name, such as
db, rather than a hard-coded container IP. Confirm both services are on the same Compose network. - A staging override cannot find a relative file. Compose resolves paths in merged files from the first file’s directory. Adjust the path or place the referenced file relative to the base file.
- One branch’s stack interferes with another. Start, execute, and tear down each run with the same unique
-pproject name. - The browser sees development code rather than the image version. Check for a host bind mount in the effective configuration; remove it from staging when image fidelity is required.
- Test data remains or disappears unexpectedly.
docker compose downremoves containers and networks but normally retains named volumes. Usedown --volumesonly when a full data reset is intended. - Secrets appear in configuration or logs. Avoid checked-in passwords and ordinary environment variables for sensitive values; use Compose secrets and check application logging and secret-file handling.
Or skip the browser setup
If your web tests need screenshots of pages, ScreenshotNeo provides a one-request screenshot API as an alternative to installing and maintaining browser capture code. For a straightforward test capture, save the response as an image:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for API options. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up for free.
Frequently Asked Questions
Does a separate Compose file have to be maintained for each environment?
No. A shared Compose file can use profiles for optional services, while override files can express environment-specific setting changes.
Does `docker compose down` delete my database data?
It removes the project’s containers and networks, but named volumes normally remain unless you explicitly include `–volumes`.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




