Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›Playwright›Parallel test execution and sharding

Advanced Playwright Techniques

Parallel test execution and sharding

Parallel execution allows Playwright to run multiple tests simultaneously across worker processes, drastically reducing the total time required for a test suite to complete. Sharding extends this by partitioning your test suite across multiple CI machines, enabling horizontal scalability for massive projects. You should reach for these techniques once your feedback loop slows down enough to hinder developer productivity or CI pipeline throughput.

Understanding Parallelism and Worker Processes

Playwright executes tests in parallel by spawning multiple operating system processes, known as workers. Each worker operates in an isolated environment, meaning they do not share memory, cookies, or local storage, which prevents test interference. By default, Playwright uses a heuristic to determine the number of workers based on your machine's CPU cores. The primary reason this works is the architecture of the test runner, which treats each test file as a discrete unit of work that can be scheduled independently across the pool of available workers. Understanding this is critical because it forces you to write truly independent tests; if your tests rely on a specific execution order or global state modifications, parallel execution will cause non-deterministic failures. When configured correctly, parallelism shifts the performance bottleneck from the serial execution of tests to the available hardware resources of your machine or container.

// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  // Explicitly control parallelism
  workers: 4, // Run up to 4 tests in parallel
  fullyParallel: true, // Run individual test files in parallel
});

Managing Concurrency with Test Isolation

While parallel execution is powerful, it requires developers to strictly adhere to the principle of isolation. Because Playwright workers are separate processes, global variables or singleton instances defined in one test will not be accessible to another. This design choice is intentional; it guarantees that a failure in one test cannot corrupt the environment for another, making debugging significantly easier. When you write tests that require authentication, you should leverage the browser context feature instead of sharing a single global session. By creating a new context for every test, you ensure that cookies, headers, and local storage remain isolated, even when multiple tests run concurrently. If you find your tests failing only during parallel runs but passing in isolation, it is almost certainly a symptom of shared state contamination, often caused by hardcoding server-side data or database entries rather than generating unique identifiers per test execution.

// tests/auth.spec.ts
import { test } from '@playwright/test';

// Each test gets its own isolated browser context
test('User profile updates', async ({ page }) => {
  await page.goto('/profile');
  await page.fill('#username', 'unique_user_' + Date.now());
  await page.click('button#save');
});

Introduction to Test Sharding

Sharding is the process of splitting a large suite of tests into smaller, disjoint groups that can be executed across entirely different machines. Unlike parallelism, which is limited by the CPU count of a single local or CI node, sharding allows you to scale horizontally by adding more infrastructure. When you invoke Playwright with the shard parameter, the runner calculates the total number of tests and assigns a specific subset to the current worker process based on the total shard count. This is particularly useful for massive suites that take hours to run on a single machine. By distributing the load, you can ensure that the entire suite completes in a fraction of the time, provided your CI environment supports parallel job execution. The core logic relies on the runner being able to deterministic identify which tests belong to which shard, ensuring no test is skipped and no test is executed twice across the distributed infrastructure.

# Execute the first shard of three on this machine
npx playwright test --shard=1/3

# Execute the second shard of three on a different machine
npx playwright test --shard=2/3

Configuring Parallelism for Shared Resources

In real-world scenarios, tests often interact with external dependencies like databases or APIs. When running tests in parallel at high concurrency, these external resources can become overwhelmed, leading to timeout errors or connection refusal. Playwright provides a mechanism to limit concurrency globally or on a per-project basis to protect these shared resources. By understanding the interaction between worker counts and your backend capacity, you can tune the configuration for optimal throughput without destabilizing the system. It is a balancing act: too many workers may exhaust your backend's connection pool, while too few will leave your CI runner's CPUs underutilized. You should always monitor your backend performance metrics when increasing the worker limit. When external systems are not designed for high concurrency, it is often necessary to implement locking mechanisms or use dedicated test environments for each worker to avoid race conditions during database seeding or API orchestration tasks.

// playwright.config.ts
export default defineConfig({
  // Limit concurrency to avoid overloading external DBs
  workers: process.env.CI ? 2 : '50%', 
  projects: [
    { name: 'api-tests', workers: 1 } // API tests restricted to serial
  ]
});

Advanced Execution Control and Metadata

Sometimes you need to exercise fine-grained control over how tests are grouped and executed. Playwright allows for custom test filtering and metadata tagging, which can be used in conjunction with sharding to create specialized execution paths. For example, you might want to run smoke tests on every commit and deep regression tests only once per night. By tagging your tests and filtering them via command-line arguments, you create a dynamic execution model that maximizes the efficiency of your CI pipeline. Furthermore, by integrating these techniques with your build system, you can report results back to a central dashboard, ensuring that even when tests are scattered across multiple shards and nodes, you maintain a unified view of your application's health. The ultimate goal of these advanced techniques is to provide a fast, reliable feedback loop that empowers developers to iterate quickly while maintaining confidence in the stability of their codebase across every deployment cycle.

// tests/login.spec.ts
import { test } from '@playwright/test';

// Use metadata to group tests for specific shards
test('Critical login flow', { tag: '@smoke' }, async ({ page }) => {
  await page.goto('/login');
  // ... test implementation
});

// Command: npx playwright test --grep @smoke

Key points

  • Parallelism utilizes multiple OS processes to execute test files independently.
  • Browser contexts provide the isolation necessary for parallel tests to run without side effects.
  • Worker counts should be balanced against the hardware capacity and the load limitations of your backends.
  • Sharding enables horizontal scaling by splitting tests across multiple physical CI machines.
  • Tests must be designed to be completely independent to benefit from parallel execution.
  • Hardcoding shared state, such as specific database IDs, will inevitably cause race conditions during parallel runs.
  • Command-line flags allow for dynamic control over shards, enabling efficient CI pipeline utilization.
  • Strategic tagging and filtering ensure that only relevant test sets are executed in specific environments.

Common mistakes

  • Mistake: Sharing state between tests. Why it's wrong: Parallel tests run in separate browser contexts; global variables or shared database states cause race conditions. Fix: Use fixtures to isolate state for each test execution.
  • Mistake: Over-relying on global setup for every test. Why it's wrong: Global setups run once and cannot easily share modified state across parallel workers. Fix: Use project-level dependencies or individual test-level setup logic.
  • Mistake: Misconfiguring shard counts relative to total test count. Why it's wrong: If you have 5 tests and 10 shards, 5 shards remain idle, wasting resources. Fix: Ensure the number of tests is significantly higher than or a multiple of your shard count.
  • Mistake: Using `test.only` while running with sharding. Why it's wrong: It causes specific shards to return zero tests, leading to failures in CI pipelines that expect every shard to produce a report. Fix: Avoid focused tests in CI pipelines and use grep patterns instead.
  • Mistake: Assuming parallel execution order is deterministic. Why it's wrong: Workers pick up tests as they become free; relying on chronological order leads to flaky tests. Fix: Write tests that are completely independent and can run in any sequence.

Interview questions

What is the basic concept of parallel test execution in Playwright and how do you enable it?

Parallel test execution in Playwright allows you to run multiple test files simultaneously, which significantly reduces the total time required for a test suite to complete. By default, Playwright runs test files in parallel using worker processes. You can control this behavior in the playwright.config.ts file by adjusting the 'workers' property. Setting it to a specific number like 'workers: 4' limits execution to four concurrent processes. This is essential for modern CI/CD pipelines where feedback speed is critical for developer productivity.

How does Playwright handle isolation when running tests in parallel?

Playwright ensures isolation by assigning each test file to its own dedicated worker process. Each worker operates with its own browser context, which acts like a fresh, incognito session. This means cookies, local storage, and sessions are not shared between tests, preventing state pollution. Because each test file is independent and isolated, you can confidently run tests in parallel without worrying about interference, race conditions, or cross-test data dependencies, which is a major advantage for test stability.

What is the difference between project-level parallelism and test-level sharding?

Project-level parallelism controls how many tests within a single suite run at the same time on one machine by adjusting the worker count in the configuration file. Sharding, conversely, is a strategy used to split a massive test suite across multiple separate machines or CI containers. While parallelism optimizes time on one environment, sharding is designed to scale horizontally across many environments simultaneously. You use the --shard flag, for example, '--shard=1/4', to execute only a specific subset of tests per container, effectively dividing the total execution time by the number of shards used.

How would you compare the use of 'test.describe.configure({ mode: 'parallel' })' versus configuring workers globally?

Global worker configuration sets the maximum number of parallel processes for the entire project, defining the overall hardware concurrency limit for your test run. In contrast, 'test.describe.configure({ mode: 'parallel' })' is a granular approach that enables individual tests within a single file to execute in parallel with each other. While global settings are best for overall resource management, using 'mode: parallel' within a file is useful when you have a large number of independent tests inside one file that would otherwise execute sequentially. However, you must ensure those specific tests are truly independent to avoid collisions.

What challenges might you face when implementing parallel execution, and how does Playwright help mitigate them?

The primary challenge with parallel execution is shared state, such as database entries or global session tokens. If two tests attempt to modify the same user account simultaneously, the tests will fail. Playwright mitigates this by providing distinct browser contexts and isolating workers. To further address state issues, I often use unique data per test, such as generating random usernames, or utilize Playwright's 'beforeAll' and 'afterAll' hooks carefully. If absolute isolation is needed for specific tests that share a global resource, I would use 'test.describe.configure({ mode: 'serial' })' to force those specific tests to run sequentially while keeping the rest of the suite parallel.

Explain how to implement sharding in a CI/CD pipeline and why you would choose this over simply increasing local worker counts?

Sharding is implemented by passing the '--shard=x/y' argument to the Playwright command, where 'x' is the current shard index and 'y' is the total number of shards. This is superior to increasing local worker counts because there is a physical limit to the CPU and memory of a single machine. Once you hit that ceiling, adding more workers will cause performance degradation. Sharding bypasses this hardware limitation by spreading the load across multiple CI nodes, each with its own resources. This allows even massive test suites consisting of thousands of tests to complete in just a few minutes, which is impossible on a single-node setup regardless of worker count.

All Playwright interview questions →

Check yourself

1. When Playwright runs tests in parallel, how is isolation maintained?

  • A.By running tests in a single browser instance with cleared cookies
  • B.By utilizing independent Browser Contexts for each test
  • C.By utilizing different operating system processes for every step
  • D.By assigning a unique port to every test file
Show answer

B. By utilizing independent Browser Contexts for each test
Playwright creates a fresh Browser Context for every test, ensuring cookies, local storage, and sessions are isolated. The other options are incorrect because single-instance sessions are not fully isolated, separate processes are unnecessary for context isolation, and port assignment is not the mechanism for browser state isolation.

2. What happens when you execute tests with '--shard=1/3'?

  • A.Playwright runs only the first test file in the suite
  • B.Playwright splits the total test count and runs the first third of them
  • C.Playwright identifies the test suite, sorts it, and executes the designated fraction
  • D.Playwright runs all tests but limits the output to one-third of the total results
Show answer

C. Playwright identifies the test suite, sorts it, and executes the designated fraction
Sharding distributes the full set of tests across multiple machines by sorting them to ensure deterministic distribution. It does not just pick a subset based on file order or file count; it slices the execution list based on the shard index.

3. Why might increasing the number of workers lead to test failures in an existing suite?

  • A.Because Playwright cannot handle more than 4 concurrent workers
  • B.Because the application backend cannot handle concurrent requests from the same user session
  • C.Because the machine RAM is automatically halved to save energy
  • D.Because Playwright disables network interception when workers exceed two
Show answer

B. Because the application backend cannot handle concurrent requests from the same user session
If tests share a common database state or user account without proper isolation, increasing concurrency causes conflicts. The other options are false because Playwright supports many workers, memory management is not automated in that way, and network interception remains active.

4. How does Playwright determine how many tests to run in parallel by default?

  • A.It uses a fixed value of 2 workers
  • B.It calculates the number of physical CPU cores available on the machine
  • C.It sets the worker count to the total number of test files
  • D.It runs all tests simultaneously regardless of machine resources
Show answer

B. It calculates the number of physical CPU cores available on the machine
By default, Playwright uses a heuristic based on the number of available CPU cores to optimize performance. A fixed value of 2 or running all at once would be inefficient or crash the system, and tying it to test file counts is not the standard optimization strategy.

5. What is the primary benefit of sharding in a CI/CD pipeline?

  • A.It forces tests to run faster by skipping unnecessary setup steps
  • B.It allows test execution to be distributed across multiple physical machines to reduce total time
  • C.It automatically retries only the failed tests in the final shard
  • D.It enables cross-browser testing for a single test case
Show answer

B. It allows test execution to be distributed across multiple physical machines to reduce total time
Sharding enables parallelizing the execution of the entire suite across different machines, drastically reducing CI wall-clock time. It doesn't skip setup, handle retries differently, or specifically target cross-browser testing as its primary function.

Take the full Playwright quiz →

← PreviousWorking with authentication and sessionsNext →Integrating Playwright with CI/CD pipelines

Playwright

37 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app