level 07 / parallel-execution

Parallel Execution & Sharding

Speed up Playwright suites with workers, projects, and CI sharding across machines.

Parallelism Levels

Playwright has three parallelism layers:

LevelConfigWhere
Workers (threads)workers: NSingle machine
Projectsprojects: [...]Cross-browser / multi-config
Sharding--shard=N/MMultiple CI machines

Workers (Intra-Machine)

// playwright.config.ts
export default defineConfig({
  workers: process.env.CI ? 2 : '50%',  // CI: fixed 2; local: half CPU cores
  fullyParallel: true,                   // tests within a file run in parallel
});

Isolation requirement: Each worker gets a fresh browser context. Tests must not share state via module-level variables — use fixtures.

// ❌ Shared state — breaks parallel execution
let page: Page;
test.beforeAll(async ({ browser }) => { page = await browser.newPage(); });
test('test 1', async () => { /* uses shared page */ });

// ✅ Fixture-isolated
test('test 1', async ({ page }) => { /* fresh page per test */ });

test.describe.configure

Force serial execution for a test group that shares state:

test.describe.configure({ mode: 'serial' });

test.describe('shopping cart flow', () => {
  test('add item', async ({ page }) => { /* ... */ });
  test('checkout',  async ({ page }) => { /* ... */ });
  test('confirm',   async ({ page }) => { /* ... */ });
});

Use sparingly — prefer stateless tests.

Projects (Cross-Browser)

export default defineConfig({
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox',  use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit',   use: { ...devices['Desktop Safari'] } },
    { name: 'mobile',   use: { ...devices['iPhone 14'] } },
  ],
});

Run a single project: npx playwright test --project=chromium

Sharding (Inter-Machine CI)

Split the test suite across N CI machines:

# Machine 1
npx playwright test --shard=1/4 --reporter=blob

# Machine 2
npx playwright test --shard=2/4 --reporter=blob

# Machine 3
npx playwright test --shard=3/4 --reporter=blob

# Machine 4
npx playwright test --shard=4/4 --reporter=blob

# After all machines: merge blob reports
npx playwright merge-reports --reporter html ./blob-reports/

Playwright distributes tests evenly by file. A 400-test suite with 4 shards ≈ 100 tests per shard.

Estimating Parallelism ROI

Serial time   = sum(test durations) = 400 tests × 2 s = 800 s
Workers × 4   = 800 / 4 = 200 s per machine
Shards × 4    = 200 / 4 = 50 s total (+ startup overhead ~30 s)

Result: 800 s → ~80 s (10× improvement)

Diminishing returns: >8 workers per machine causes browser memory pressure. Profile before adding more.

--grep for Selective Runs

# Run only smoke tests
npx playwright test --grep "@smoke"

# Exclude slow tests
npx playwright test --grep-invert "@slow"

# Tag tests
test('critical login flow @smoke', async ({ page }) => { /* ... */ });

Timeout Tuning

export default defineConfig({
  timeout: 30_000,                 // per-test timeout (default: 30 s)
  expect: { timeout: 5_000 },      // per-assertion timeout (default: 5 s)
  globalTimeout: 600_000,          // whole suite timeout (default: none)
});

// Override per test
test('slow migration test', async ({ page }) => {
  test.setTimeout(120_000);
  // ...
});