skip to content

Worker Lifetime

A worker is an OS process running one test at a time with its own browser, thrown away after any failure. Interviewers ask because it explains why no state leaks forward between tests.

on this pageshow

explore

questions

5

In Playwright, what does the workers option control and what is its default value?

level: juniorimportance: must knowfreq 72%

answer

  1. Parallelism comes from processes, not threads
  2. One test at a time per process
  3. The default is derived from CPU cores
  4. Half of logical cores by default
  5. Config workers, or --workers and -j

basics

~20 s

The workers option sets how many test processes Playwright runs at once, each running one test at a time. It defaults to half the machine's logical CPU cores, and --workers or -j overrides it for a run.

solid answer

~40 s

A Playwright worker is an operating-system process that imports your test files, launches its own browser, and runs one test at a time, so parallelism comes from running several workers side by side. The `workers` option is the ceiling on how many are alive at once. With nothing set, Playwright 1.63 uses half of the machine's logical CPU cores, which leaves headroom for the browsers those workers drive. You can pin it in `playwright.config.ts` as an absolute number (`workers: 4`) or as a share of the cores (`workers: '50%'`), and `--workers=4` (short form `-j 4`) overrides the config for a single run. `workers: 1` gives you one process and a strictly sequential run. It is a ceiling, not a promise: if only two units of work remain, only two workers run.

code

typescript · 8 lines
typescript
import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests/payroll',
  // Unset locally means half the logical CPU cores; CI gets an explicit count
  // because the default is computed from the host's cores, not the container's.
  workers: process.env.CI ? 4 : undefined,
});

go deeper

for a junior

Remember that a worker is a separate process running one test at a time, that the default is half the machine's logical CPU cores, and that --workers or -j changes it for a single run.

for a middle

Be able to explain why half the cores is the default: each worker drives a browser that needs CPU of its own, so sizing workers to the full core count oversubscribes the machine and turns timeouts into false failures.

for a senior

Show that you verify the count actually used from the run header rather than trusting the config, and that you pick a number from the CI container's real CPU and memory allowance and the backend's capacity.

for a principal

Own the policy: one number cannot be right on laptops and build agents alike, so decide where the count is expressed, whether it is absolute or a share of cores, and what evidence justifies changing it.

## What a worker is A **worker** is a separate operating-system process that the Playwright test runner starts to execute tests. Each worker imports the test files it is handed, launches its own browser, and runs **one test at a time** — there is no concurrency inside a worker. All of a run's parallelism therefore comes from having several worker processes alive simultaneously, and the `workers` option is the ceiling on that number. Because a worker is a real process, everything it holds is private to it: module-level variables in your test files, the browser it launched, any connection pool it opened. Nothing crosses the process boundary except what a test deliberately writes to disk or to a shared service. ## Setting the number Three inputs decide the count, each overriding the one before it: 1. **The default.** In Playwright 1.63, with nothing configured, the runner uses half of the machine's logical CPU cores. 2. **The config file.** `workers` in `playwright.config.ts`, given either as an absolute number (`workers: 4`) or as a share of the logical cores (`workers: '50%'`). 3. **The command line.** `--workers=4`, with `-j` as the short form, which wins over the config for that run. | Value | What you get | |---|---| | unset | the default: half the logical CPU cores | | `workers: 1` | one process; each test runs after the one before it | | `workers: 4` | at most four processes, so four tests in flight | | `workers: '50%'` | half the logical cores, resolved on whichever machine runs | ## Why half the cores instead of all of them Each worker drives a real browser, and a browser is itself a multi-process program: renderer, GPU and network work all burn CPU outside the test process. Sizing the worker count to the full core count leaves nothing for the browsers those workers are driving. The machine oversubscribes, every action and navigation wait stretches, and tests that were comfortably inside their timeout start failing for reasons that have nothing to do with the application. Half the cores is a deliberately conservative starting point that leaves room for the browsers, the operating system and — on a laptop — the rest of your desktop. ## What the option does not decide - **It is a ceiling, not a quota.** If three units of work remain, three workers run, however high the number is set. - **It does not group your tests.** The runner hands a free worker the next available unit of work; how tests are grouped into those units is a different setting entirely. - **It does not speed up a single worker.** Doubling the number gives you twice as many processes, not a faster one; a worker still runs its tests one after another. - **It does not survive a failure.** A worker whose test fails is discarded and replaced, and the replacement counts against the same ceiling. ## Choosing a number for a payroll regression suite in CI For a large payroll regression suite, the default is a starting point rather than an answer: - **On a developer machine, leave it unset.** Half the cores keeps the laptop usable while a long suite runs. - **In CI, pin it.** The default is derived from the cores the operating system reports, which is normally the host's core count rather than the container's CPU allowance. - **Watch memory, not only CPU.** Every worker runs its own browser, costing hundreds of megabytes; a container generous with cores and stingy with RAM will lose workers to the kernel before CPU is the limit. - **Remember the far side of the wire.** Twelve workers means twelve concurrent sessions against the payroll backend; if that environment cannot serve them, the suite goes flaky for reasons the browsers never caused. ## Confirming what was actually used Do not assume the number you configured is the number in force — a stray `-j` in a CI script silently wins. The `list` and `line` reporters open with a header naming how many tests are running and how many workers are running them, and that single line is the fastest way to confirm the setting took effect before you start tuning anything else.

  • How would you make one payroll suite run strictly sequentially without touching the config file?
    Pass `--workers=1` (or `-j 1`) on the command line for that run. The CLI flag overrides the configured value, so a single process picks up every test and runs them one after another, with no other file edited and nothing left behind for the next run.
  • Why express the worker count as a percentage rather than a fixed number?
    A percentage such as `workers: '50%'` is resolved against the logical cores of whichever machine runs the suite, so one config behaves sensibly on a four-core laptop and a sixteen-core build agent. A fixed number is right on exactly one machine shape and either starves or oversubscribes everywhere else.

saying these in an interview costs you the question

  • Says Playwright runs tests in threads inside one process
  • Thinks a worker runs several tests concurrently
  • Claims the default is one worker per test file
  • Assumes the default uses every logical CPU core
  • Believes raising workers always shortens the run
  • Thinks the config value cannot be overridden per run
open as a page

What happens to a Playwright worker process when one of its tests fails?

level: middleimportance: must knowfreq 58%

basics

~20 s

Playwright throws the worker away. The process is shut down after the failure and a fresh worker process, with a new browser, picks up the remaining tests, so nothing the failing test left behind reaches them.

open as a page

In Playwright, how do testInfo.workerIndex and testInfo.parallelIndex differ?

level: middleimportance: should knowfreq 42%

basics

~20 s

workerIndex names a process and never repeats: every worker a run starts, including replacements after failures, gets a new one. parallelIndex names a slot between zero and workers minus one, and a replacement worker inherits it.

open as a page

Playwright's default worker count makes your payroll suite time out in a CPU-limited CI container - how do you diagnose and fix it?

level: seniorimportance: should knowfreq 36%

basics

~20 s

The default is half the cores the operating system reports, which is usually the host's, not the container's CPU allowance. Read the worker count from the run header, compare it with the container limit, then pin workers explicitly.

open as a page

Playwright discards a worker process after any test failure - what does that guarantee cost a large suite?

level: principalimportance: should knowfreq 30%

basics

~20 s

It buys certainty that no test inherits a process a failure left dirty. It costs a cold browser launch plus per-worker set-up for every failure, so a red payroll run is measurably slower than a green one.

open as a page