Cypress tests depend on system-level libraries (libnss, libatk, libgtk), specific browser versions, and a correctly configured display server. Installing these dependencies on every developer’s machine and every CI runner is tedious and error-prone. Docker solves this: the official Cypress Docker images include everything pre-installed — browsers, system libraries, Node.js, and Cypress itself. One docker run command gives you a reproducible test environment that works identically on macOS, Linux, Windows, and every CI platform.
Official Cypress Docker Images
Cypress maintains several Docker image variants, each tailored to a specific use case.
// ── Cypress Docker image variants ──
const DOCKER_IMAGES = [
{
image: 'cypress/base',
contains: 'Node.js + OS dependencies (no browsers)',
size: '~800 MB',
use: 'When you install Cypress and browsers yourself',
},
{
image: 'cypress/browsers',
contains: 'Node.js + OS deps + Chrome + Firefox + Edge',
size: '~2.5 GB',
use: 'Most common — run tests on any included browser',
},
{
image: 'cypress/included',
contains: 'Everything in browsers + Cypress pre-installed',
size: '~3 GB',
use: 'Zero-install: just mount your project and run',
},
];
// ── Using cypress/included — the fastest way to run ──
/*
# Run tests with zero installation
docker run -it \
-v $(pwd):/e2e \
-w /e2e \
cypress/included:13.7.0 \
--browser chrome
# Explanation:
# -v $(pwd):/e2e → Mount your project into the container
# -w /e2e → Set working directory to your project
# cypress/included → Image with everything pre-installed
# --browser chrome → Run on Chrome
*/
// ── Docker Compose for app + tests ──
const DOCKER_COMPOSE = `
# docker-compose.cypress.yml
version: '3.8'
services:
# Your application
app:
build: .
ports:
- '3000:3000'
environment:
- NODE_ENV=test
- DATABASE_URL=postgres://db:5432/testdb
# Test database
db:
image: postgres:16
environment:
POSTGRES_DB: testdb
POSTGRES_PASSWORD: test
# Cypress test runner
cypress:
image: cypress/included:13.7.0
depends_on:
- app
environment:
- CYPRESS_BASE_URL=http://app:3000
- CYPRESS_VIDEO=false
working_dir: /e2e
volumes:
- ./:/e2e
- /e2e/node_modules # Exclude host node_modules
command: --browser chrome
`;
// ── Dockerfile for custom Cypress image ──
const CUSTOM_DOCKERFILE = `
# Dockerfile.cypress
FROM cypress/browsers:latest
WORKDIR /app
# Install project dependencies (cached layer)
COPY package.json package-lock.json ./
RUN npm ci
# Copy test files
COPY cypress/ ./cypress/
COPY cypress.config.ts ./
# Default command
CMD ["npx", "cypress", "run", "--browser", "chrome"]
`;
// ── Docker best practices for Cypress ──
const DOCKER_BEST_PRACTICES = [
'Use cypress/included for zero-install, cypress/browsers for custom setups',
'Pin image versions (cypress/included:13.7.0, not :latest) for reproducibility',
'Exclude host node_modules with a volume mount to avoid platform conflicts',
'Set CYPRESS_VIDEO=false in containers to save disk space and upload time',
'Use depends_on with health checks to ensure the app is ready before tests run',
'Mount only necessary files — exclude .git, build artifacts, IDE configs',
'Set shm_size: 2g if Chrome crashes with out-of-memory errors in Docker',
];
console.log('Cypress Docker Images:');
DOCKER_IMAGES.forEach(img => {
console.log(`\n ${img.image}`);
console.log(` Contains: ${img.contains}`);
console.log(` Size: ${img.size}`);
console.log(` Use: ${img.use}`);
});
cypress/included image contains Cypress itself pre-installed as a global npm package. You do not need to run npm install or npx cypress install — the container is ready to execute tests immediately. Just mount your project directory and run. This eliminates the single slowest step in most CI pipelines: installing Cypress (which downloads a ~300MB binary). For teams that customise their Cypress installation (plugins, preprocessors), cypress/browsers is more appropriate because it lets you run npm ci with your own package.json.docker compose up command. The depends_on directive ensures the app starts before Cypress, and CYPRESS_BASE_URL=http://app:3000 uses Docker’s internal networking so Cypress reaches the app without exposing ports to the host. This setup produces a fully self-contained test environment that any team member can start with one command.cypress/included:13.7.0, not cypress/included:latest. The :latest tag changes when new versions are released, potentially introducing breaking changes in your CI pipeline without any code change on your side. Pinned versions ensure your test environment is identical today, next week, and next month. Update the version deliberately in a PR where you can verify compatibility.Common Mistakes
Mistake 1 — Using :latest tag for Cypress Docker images
❌ Wrong: cypress/included:latest — CI pipeline breaks unexpectedly when Cypress releases a new version.
✅ Correct: cypress/included:13.7.0 — pinned version, updated deliberately via a PR with test verification.
Mistake 2 — Mounting host node_modules into the container
❌ Wrong: Host node_modules (compiled for macOS) are mounted into a Linux container — native modules crash with incompatible binary errors.
✅ Correct: Add - /e2e/node_modules as an anonymous volume to exclude host node_modules, and run npm ci inside the container.