When to use: Running Playwright tests in containers for reproducible environments, CI pipelines, or local development with consistent browser versions. Essential when your team needs identical test environments across machines.
# Official Playwright Docker images
docker pull mcr.microsoft.com/playwright:v1.52.0-noble # Ubuntu 24.04, all browsers
docker pull mcr.microsoft.com/playwright:v1.52.0-jammy # Ubuntu 22.04, all browsers
# Run tests in container
docker run --rm -v $(pwd):/app -w /app mcr.microsoft.com/playwright:v1.52.0-noble \
npx playwright test
# Check your Playwright version (must match image tag)
npx playwright --versionUse when: Quick, reproducible test runs without building a custom image. Avoid when: You need application services (database, API) running alongside -- use docker-compose instead.
# Run all tests
docker run --rm \
-v $(pwd):/app \
-w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"
# Run with environment variables
docker run --rm \
-v $(pwd):/app \
-w /app \
-e CI=true \
-e BASE_URL=http://host.docker.internal:3000 \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"
# Run and extract report
docker run --rm \
-v $(pwd):/app \
-w /app \
-v $(pwd)/playwright-report:/app/playwright-report \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"Use when: You need additional system dependencies, pre-installed npm packages, or a smaller image with only certain browsers. Avoid when: The official image works as-is.
# Dockerfile.playwright
FROM mcr.microsoft.com/playwright:v1.52.0-noble
WORKDIR /app
# Copy package files first for better layer caching
COPY package.json package-lock.json ./
RUN npm ci
# Copy the rest of the project
COPY . .
# Default command
CMD ["npx", "playwright", "test"]# Build and run
docker build -f Dockerfile.playwright -t my-e2e-tests .
docker run --rm my-e2e-tests
# Run with specific options
docker run --rm my-e2e-tests npx playwright test --project=chromium
# Extract report
docker run --rm -v $(pwd)/reports:/app/playwright-report my-e2e-testsSlim image with only Chromium:
# Dockerfile.playwright-chromium
FROM node:20-slim
# Install only Chromium dependencies
RUN npx playwright install --with-deps chromium
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
CMD ["npx", "playwright", "test", "--project=chromium"]Use when: Tests need the full application stack: web server, database, cache, and Playwright running together. Avoid when: Tests run against a remote environment (staging/prod) -- no local services needed.
# docker-compose.yml
services:
# Application under test
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=test
- DATABASE_URL=postgresql://postgres:postgres@db:5432/test
- REDIS_URL=redis://cache:6379
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
# Database
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
tmpfs:
- /var/lib/postgresql/data # RAM disk for speed
# Cache
cache:
image: redis:7-alpine
# Playwright test runner
e2e:
image: mcr.microsoft.com/playwright:v1.52.0-noble
working_dir: /app
volumes:
- .:/app
- /app/node_modules # prevent host node_modules from overriding
environment:
- CI=true
- BASE_URL=http://app:3000
depends_on:
- app
command: bash -c "npm ci && npx playwright test"
profiles:
- test # only start with: docker compose --profile test up# Run the full stack with tests
docker compose --profile test up --abort-on-container-exit --exit-code-from e2e
# Run just the app (for local dev)
docker compose up app
# Run tests against already-running stack
docker compose --profile test run --rm e2e npx playwright test
# Tear down everything
docker compose --profile test down -vUse when: You need test artifacts (HTML reports, traces, screenshots) accessible on the host after container tests complete. Avoid when: CI handles artifact collection natively (GitHub Actions, GitLab artifacts).
# Method 1: Bind mount the output directories
docker run --rm \
-v $(pwd):/app \
-v $(pwd)/playwright-report:/app/playwright-report \
-v $(pwd)/test-results:/app/test-results \
-w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"
# Method 2: Copy artifacts from a stopped container
docker run --name e2e-run \
-v $(pwd):/app \
-w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test" || true
docker cp e2e-run:/app/playwright-report ./playwright-report
docker cp e2e-run:/app/test-results ./test-results
docker rm e2e-run
# View the report
npx playwright show-report ./playwright-reportDocker Compose for report extraction:
# docker-compose.yml (add to e2e service)
services:
e2e:
image: mcr.microsoft.com/playwright:v1.52.0-noble
working_dir: /app
volumes:
- .:/app
- ./playwright-report:/app/playwright-report
- ./test-results:/app/test-results
# ... rest of configUse when: Your CI environment benefits from containerized test execution.
GitHub Actions -- container job:
# .github/workflows/playwright.yml
jobs:
test:
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.52.0-noble
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright test
env:
HOME: /rootGitLab CI -- image directive:
# .gitlab-ci.yml
test:
image: mcr.microsoft.com/playwright:v1.52.0-noble
script:
- npm ci
- npx playwright testJenkins -- Docker agent:
// Jenkinsfile
pipeline {
agent {
docker {
image 'mcr.microsoft.com/playwright:v1.52.0-noble'
args '-u root'
}
}
stages {
stage('Test') {
steps {
sh 'npm ci'
sh 'npx playwright test'
}
}
}
}Use when: Your team uses VS Code Dev Containers or GitHub Codespaces and needs Playwright available in the development environment. Avoid when: Everyone installs Playwright locally and version differences don't cause issues.
// .devcontainer/devcontainer.json
{
"name": "Playwright Dev",
"image": "mcr.microsoft.com/playwright:v1.52.0-noble",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
}
},
"postCreateCommand": "npm ci",
"customizations": {
"vscode": {
"extensions": [
"ms-playwright.playwright"
]
}
},
"forwardPorts": [3000, 9323],
"remoteUser": "root"
}| Scenario | Approach | Why |
|---|---|---|
| Simple CI pipeline | Official Playwright image as CI image | Browsers pre-installed; zero browser install time |
| Tests need database + cache | Docker Compose with app, db, cache, e2e services | Full stack in isolated containers |
| Team needs identical environments | Dev Container or custom Dockerfile | Eliminate "works on my machine" |
| Only testing Chromium | Slim image: node:20-slim + install --with-deps chromium |
Smaller image, faster pulls |
| Cross-browser testing | Official Playwright image (has all browsers) | All three engines pre-installed |
| Local development | Run directly on host, not in container | Faster iteration, easier debugging |
| CI with artifact extraction | Bind mount report/results dirs or use CI artifact upload | Reports accessible after container exits |
| Image | Size | Browsers | Base OS |
|---|---|---|---|
mcr.microsoft.com/playwright:v1.52.0-noble |
~2 GB | Chromium, Firefox, WebKit | Ubuntu 24.04 |
mcr.microsoft.com/playwright:v1.52.0-jammy |
~2 GB | Chromium, Firefox, WebKit | Ubuntu 22.04 |
| Custom slim (Chromium only) | ~800 MB | Chromium | Depends on base |
| Anti-Pattern | Problem | Do This Instead |
|---|---|---|
Image tag doesn't match @playwright/test version |
Browser binaries incompatible with Playwright library | Always match: v1.52.0 image for @playwright/test@1.52.0 |
Using latest tag |
Unpredictable; image updates can break tests | Pin to exact version: v1.52.0-noble |
| Installing browsers inside container at runtime | Wastes 60-90 seconds on every run | Use official image (browsers pre-installed) or build custom image with browsers baked in |
| Running as non-root without configuring sandbox | Chromium sandbox fails with permission errors | Run as root (-u root) or disable sandbox (--no-sandbox in launch args) |
Bind-mounting node_modules from host |
Platform-specific binaries (macOS vs Linux) cause crashes | Use anonymous volume: -v /app/node_modules |
| No health checks on dependent services | Tests start before database is ready | Add healthcheck to db service; use depends_on: condition: service_healthy |
| Building application inside the Playwright container | Large image, slow builds, wrong base for your app | Separate app and e2e containers in docker-compose |
Cause: Playwright version in package.json doesn't match the Docker image version.
Fix: Ensure exact version match:
# Check your version
npm ls @playwright/test
# @playwright/test@1.52.0
# Use matching image
docker pull mcr.microsoft.com/playwright:v1.52.0-nobleCause: Tests are trying to reach localhost:3000 but the app is in a different container.
Fix: Use the service name as hostname and configure baseURL:
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
baseURL: process.env.BASE_URL || 'http://localhost:3000',
},
// Disable webServer in Docker -- app is managed by docker-compose
...(process.env.CI ? {} : {
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: true,
},
}),
});# docker-compose.yml
e2e:
environment:
- BASE_URL=http://app:3000 # "app" is the service nameCause: Container runs as root but host files are owned by your user, or vice versa.
Fix: Match user IDs or run as root:
# Run as your host user
docker run --rm -u $(id -u):$(id -g) \
-v $(pwd):/app -w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
npx playwright test
# Or run as root (simpler, fine for CI)
docker run --rm \
-v $(pwd):/app -w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
npx playwright testCause: Docker Desktop on macOS/Windows has I/O overhead for bind-mounted volumes.
Fix: Copy files into the container instead of mounting:
# Dockerfile.playwright
FROM mcr.microsoft.com/playwright:v1.52.0-noble
WORKDIR /app
COPY . .
RUN npm ci
CMD ["npx", "playwright", "test"]Or use delegated mount on macOS:
docker run --rm \
-v $(pwd):/app:delegated \
-w /app \
mcr.microsoft.com/playwright:v1.52.0-noble \
bash -c "npm ci && npx playwright test"- ci/ci-github-actions.md -- container jobs in GitHub Actions
- ci/ci-gitlab.md -- Docker images in GitLab CI
- ci/ci-other.md -- Docker agents in Jenkins, CircleCI
- ci/parallel-and-sharding.md -- sharding within containers
- ci/reporting-and-artifacts.md -- extracting reports from containers