Skip to main content
Back to Blog
Reference
2026-05-22

Playwright Config Options: Complete 2026 Reference

Every Playwright config option in 2026: testDir, retries, projects, use, webServer, reporter, snapshotPath, and full TypeScript reference.

Playwright Test Config Options: Complete 2026 Reference

playwright.config.ts is the single source of truth for how your test suite runs. Every flag you can pass on the command line, every project you can target, every artifact you can produce, every fixture you can configure, lives here. The default config that Playwright generates is intentionally minimal; the real config you ship to production carries dozens of options whose effects compound across hundreds of tests.

This reference enumerates every option available on defineConfig in Playwright 1.49+, with examples for each. Every option is grouped by purpose; every value is a real production setting from the QAskills.sh team's own pipelines.

For broader fundamentals, see the Playwright E2E Complete Guide. The playwright-e2e skill helps AI assistants choose sensible defaults when generating configs.

Top-level structure

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 4 : undefined,
  reporter: 'html',
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
  ],
  webServer: {
    command: 'pnpm dev',
    port: 3000,
    reuseExistingServer: !process.env.CI,
  },
});

Test discovery options

OptionTypeDefaultPurpose
testDirstring.Root directory for tests
testMatchstring | RegExp | Array`**/*.@(spectest).?(c
testIgnorestring | RegExp | Array**/node_modules/**Files to exclude
fullyParallelbooleanfalseTests within a file run in parallel
forbidOnlybooleanfalseFail if test.only is committed
globalSetupstring(none)Path to global setup script
globalTeardownstring(none)Path to global teardown script

forbidOnly: !!process.env.CI is the recommended setting; CI fails when test.only slips into a PR.

Execution options

OptionTypeDefaultPurpose
workersnumber | string(half cores)Worker process count
timeoutnumber30_000Per-test timeout (ms)
globalTimeoutnumber0 (disabled)Total suite timeout (ms)
retriesnumber0Retries on failure
maxFailuresnumber0 (disabled)Stop after N failures
expect.timeoutnumber5000Default expect timeout (ms)
updateSnapshotsstring'missing'Snapshot update mode
quietbooleanfalseSuppress stdout
shardobject(none)Sharding via CLI usually
export default defineConfig({
  timeout: 30_000,
  expect: { timeout: 10_000 },
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 4 : undefined,
  maxFailures: process.env.CI ? 10 : 0,
});

Project structure

projects: [
  { name: 'setup', testMatch: /.*\.setup\.ts/ },
  {
    name: 'chromium',
    use: { ...devices['Desktop Chrome'] },
    dependencies: ['setup'],
  },
  {
    name: 'firefox',
    use: { ...devices['Desktop Firefox'] },
  },
],

Each project can override almost every config field for its tests.

Project fieldPurpose
nameProject identifier
testDirOverride testDir
testMatch / testIgnoreOverride discovery
usePer-project options
dependenciesRun other projects first
teardownProject to run after
grep / grepInvertFilter tests by tag
metadataFree-form key/value
outputDirOverride outputDir
snapshotDirOverride snapshotDir
fullyParallelOverride parallel mode
retriesOverride retries
timeoutOverride timeout

use options (per-test context)

The use block configures every browser context the test sees.

OptionPurpose
baseURLPrefix for relative URLs in page.goto
viewportInitial viewport ({ width, height } or null)
deviceScaleFactorDPI ratio
isMobileMobile emulation
hasTouchTouch support
userAgentOverride User-Agent
localeBCP 47 locale
timezoneIdIANA timezone
geolocation{ latitude, longitude }
permissionsArray of permissions
colorScheme'light' / 'dark' / 'no-preference'
reducedMotion'reduce' / 'no-preference'
forcedColors'active' / 'none'
storageStatePath or object
extraHTTPHeadersPer-context headers
httpCredentialsBasic auth
offlineSimulate offline
ignoreHTTPSErrorsBypass TLS (testing)
acceptDownloadsAllow downloads (default true)
serviceWorkers'allow' / 'block'
bypassCSPSkip Content Security Policy
proxyHTTP proxy
traceTrace mode
videoVideo mode
screenshotScreenshot mode
launchOptionsBrowser launch flags
contextOptionsAdditional context options
testIdAttributeAttribute for getByTestId
actionTimeoutPer-action timeout
navigationTimeoutPer-navigation timeout

Reporter options

reporter: [
  ['list'],
  ['html', { open: 'never', outputFolder: 'playwright-report' }],
  ['blob'],
  ['junit', { outputFile: 'test-results/junit.xml' }],
  process.env.CI ? ['github'] : ['null'],
],

For deeper coverage, see Playwright Test Reporters HTML Allure JUnit Guide.

Output options

OptionDefaultPurpose
outputDirtest-resultsWhere artifacts go
snapshotDir(next to test)Where snapshots live
snapshotPathTemplate(auto)Custom snapshot path
preserveOutput'always'When to clear output
outputDir: './test-results',
snapshotPathTemplate: '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}-{projectName}{ext}',
preserveOutput: process.env.CI ? 'never' : 'failures-only',

webServer

Spin up the app before tests; tear down after.

webServer: {
  command: 'pnpm start',
  url: 'http://localhost:3000',
  reuseExistingServer: !process.env.CI,
  timeout: 120_000,
  stdout: 'pipe',
  stderr: 'pipe',
  env: {
    PORT: '3000',
    NODE_ENV: 'test',
  },
  cwd: './',
}
OptionPurpose
commandShell command to start the server
urlWait for HTTP 200 here before tests
portAlternative: wait for port to open
reuseExistingServerSkip starting if already up
timeoutMax wait time
stdout / stderrPipe or ignore output
envEnvironment overrides
cwdWorking directory
ignoreHTTPSErrorsTLS bypass

For multiple servers:

webServer: [
  { command: 'pnpm --filter @qaskills/api start', port: 4000 },
  { command: 'pnpm --filter @qaskills/web start', port: 3000 },
],

metadata

Arbitrary key/value for reporters or downstream tools.

metadata: {
  appVersion: process.env.GITHUB_SHA ?? 'local',
  environment: process.env.ENV ?? 'dev',
  team: 'QASkills',
},

expect block

expect: {
  timeout: 10_000,
  toHaveScreenshot: {
    maxDiffPixelRatio: 0.005,
    threshold: 0.2,
    animations: 'disabled',
  },
  toMatchSnapshot: {
    maxDiffPixelRatio: 0.005,
  },
},
Sub-optionPurpose
timeoutDefault for web-first assertions
toHaveScreenshotDefaults for screenshot diffs
toMatchSnapshotDefaults for text snapshot diffs

Snapshot updates

ModeBehavior
missing (default)Write only when no baseline exists
noneNever write; always compare
allAlways write

CLI override: npx playwright test --update-snapshots.

Global setup and teardown

// global-setup.ts
import { chromium, FullConfig } from '@playwright/test';

async function globalSetup(config: FullConfig) {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  await page.goto(config.projects[0].use.baseURL!);
  await browser.close();
}

export default globalSetup;
// playwright.config.ts
globalSetup: require.resolve('./global-setup'),
globalTeardown: require.resolve('./global-teardown'),

Global setup runs once before all workers; teardown runs once after.

Environment-aware patterns

const isCI = !!process.env.CI;

export default defineConfig({
  fullyParallel: true,
  workers: isCI ? 4 : undefined,
  retries: isCI ? 2 : 0,
  reporter: isCI
    ? [['blob'], ['github']]
    : [['list'], ['html', { open: 'on-failure' }]],
  use: {
    trace: isCI ? 'on-first-retry' : 'retain-on-failure',
    screenshot: 'only-on-failure',
    video: isCI ? 'retain-on-failure' : 'off',
    baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
  },
});

The isCI switch keeps local development fast while CI gets full instrumentation.

A production config

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 4 : undefined,
  reporter: [
    ['list'],
    ['html', { open: 'never' }],
    process.env.CI ? ['blob'] : ['null'],
    ['junit', { outputFile: 'test-results/junit.xml' }],
  ],
  use: {
    baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    reducedMotion: 'reduce',
    testIdAttribute: 'data-testid',
  },
  expect: {
    timeout: 10_000,
    toHaveScreenshot: { maxDiffPixelRatio: 0.005, animations: 'disabled' },
  },
  projects: [
    { name: 'setup', testMatch: /.*\.setup\.ts/ },
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json' },
      dependencies: ['setup'],
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'], storageState: 'playwright/.auth/user.json' },
      dependencies: ['setup'],
    },
    {
      name: 'mobile-chromium',
      use: { ...devices['Pixel 8'], storageState: 'playwright/.auth/user.json' },
      dependencies: ['setup'],
    },
  ],
  webServer: {
    command: 'pnpm start',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
    timeout: 120_000,
  },
});

Common pitfalls

Pitfall 1: forbidOnly: true everywhere. Disables test.only locally too. Gate on CI.

Pitfall 2: Hard-coded baseURL. Use env var fallback for portability.

Pitfall 3: Forgetting webServer.reuseExistingServer. Without it, every CI run starts a fresh server; locally you cannot iterate fast.

Pitfall 4: workers: 1 in CI. Defeats parallelism. Use 4+ on standard runners.

Pitfall 5: Reporters not adapting to CI. Open the HTML report locally; pipe to blob in CI.

Anti-patterns

  • Putting test logic in the config. Configs configure; specs test.
  • Hard-coding paths that should be relative.
  • Skipping the projects array. Even single-project runs benefit from named projects.
  • Setting timeout per-test instead of globally. Defaults apply across the suite.

Conclusion and next steps

A well-tuned playwright.config.ts is the difference between a fast, reliable test suite and a slow, fragile one. Match settings to environment, project to browser, and instrument liberally in CI while keeping local runs lean.

Install the playwright-e2e skill so AI assistants generate configs that follow these patterns. For broader CI scaffolding, see Playwright CI GitHub Actions Complete Guide. For reporters, Playwright Test Reporters HTML Allure JUnit Guide.

Playwright Config Options: Complete 2026 Reference | QASkills.sh