playwright.config.ts Explained: Every Important Playwright Config Option

Every Playwright project is controlled by one file: playwright.config.ts. In this lesson you will learn what each important option does, how projects work, and how to build a clean, production-ready config step by step.

Advertisement

📖 What You’ll Learn: test runner options (testDir, timeout, workers, retries, reporter), the use block (baseURL, headless, viewport, screenshot, video, trace, timeouts), projects for browsers and devices, setup projects, webServer, test.use overrides and a complete annotated config.


📄 What Is playwright.config.ts?

playwright.config.ts is the control centre of your Playwright project. It sits in the project root and tells Playwright where your tests are, how to run them, which browsers to use, and what to record when something fails. Because it is a TypeScript file wrapped in defineConfig(), your editor autocompletes every option and flags typos.

Here is the config the installer generates (comments shortened):

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 ? 1 : undefined,
  reporter: 'html',
  use: {
    // baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox',  use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit',   use: { ...devices['Desktop Safari'] } },
  ],
});

The options fall into three groups: test runner options (top level), browser and context options (inside use), and projects (named variations of use). Let’s go through each.


⚙️ Test Runner Options (Top Level)

OptionWhat it doesExample
testDirFolder that contains your tests'./tests'
testMatch / testIgnoreWhich files count as tests (default: *.spec.ts and *.test.ts)'**/*.e2e.ts'
timeoutMax time for one test, default 30 seconds60_000
expect.timeoutMax time for one assertion, default 5 seconds{ timeout: 10_000 }
fullyParallelRun tests inside a file in parallel tootrue
workersNumber of parallel worker processes4 or '50%'
retriesRe-run failed tests this many times2
forbidOnlyFail the run if test.only was left in code (great for CI)!!process.env.CI
maxFailuresStop the run after N failures10
reporterHow results are reported'html', 'list', or an array
outputDirWhere screenshots, videos and traces are saved'test-results'
globalSetup / globalTeardownFiles that run once before / after all tests'./global-setup.ts'

💡 Tip: process.env.CI is set automatically by most CI systems (including GitHub Actions). The default config uses it to apply stricter settings in CI and faster ones locally.


🌐 The use Block: Browser and Context Options

Everything inside use applies to the browser, context and page that each test receives.

OptionWhat it does
baseURLLets you write page.goto('/login') instead of the full URL
headlessfalse shows the browser window (default true)
viewportBrowser window size, e.g. { width: 1280, height: 720 }
screenshot'off', 'on' or 'only-on-failure'
video'off', 'on', 'retain-on-failure' or 'on-first-retry'
trace'off', 'on', 'retain-on-failure' or 'on-first-retry'
actionTimeoutMax time for each click, fill etc. (default: no separate limit)
navigationTimeoutMax time for goto and navigations
ignoreHTTPSErrorsAccept invalid certificates on test environments
locale / timezoneIdTest in another language or time zone, e.g. 'en-IN', 'Asia/Kolkata'
storageStateStart each test already logged in (see save login session)
testIdAttributeCustom attribute for getByTestId, e.g. 'data-test'
launchOptionsLow-level options such as { slowMo: 500 } to slow down actions

A practical use block for most projects:

use: {
  baseURL: process.env.BASE_URL ?? 'https://www.saucedemo.com',
  headless: true,
  viewport: { width: 1366, height: 768 },
  screenshot: 'only-on-failure',
  video: 'retain-on-failure',
  trace: 'on-first-retry',
  actionTimeout: 15_000,
  testIdAttribute: 'data-test',
},

🧭 Projects: Browsers, Devices and Environments

A project is a named group of settings. Every test runs once per project. Projects are how you run cross-browser tests, mobile emulation, or different environments.

projects: [
  { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
  { name: 'firefox',  use: { ...devices['Desktop Firefox'] } },
  { name: 'webkit',   use: { ...devices['Desktop Safari'] } },

  // Branded browsers
  { name: 'Google Chrome',  use: { ...devices['Desktop Chrome'], channel: 'chrome' } },
  { name: 'Microsoft Edge', use: { ...devices['Desktop Edge'], channel: 'msedge' } },

  // Mobile emulation
  { name: 'Mobile Safari', use: { ...devices['iPhone 13'] } },
  { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] } },
],

Run a single project with npx playwright test --project=chromium.

Setup project: log in once for all tests

Projects can depend on each other. A common pattern is a setup project that logs in and saves the session, which other projects reuse:

projects: [
  { name: 'setup', testMatch: /.*\.setup\.ts/ },
  {
    name: 'chromium',
    use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json' },
    dependencies: ['setup'],
  },
],

🚀 webServer: Start Your App Before Testing

If you test your own application locally, Playwright can start it for you and wait until it is ready:

webServer: {
  command: 'npm run start',
  url: 'http://localhost:3000',
  reuseExistingServer: !process.env.CI,
  timeout: 120_000,
},

📋 A Complete, Annotated Config for This Course

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

export default defineConfig({
  testDir: './tests',
  timeout: 30_000,
  expect: { timeout: 7_000 },
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 2 : undefined,
  reporter: [
    ['list'],                               // readable terminal output
    ['html', { open: 'never' }],            // HTML report in playwright-report/
  ],
  use: {
    baseURL: process.env.BASE_URL ?? 'https://www.saucedemo.com',
    testIdAttribute: 'data-test',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'on-first-retry',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox',  use: { ...devices['Desktop Firefox'] } },
  ],
});

📝 Note: You can keep several config files (for example one for API tests and one for UI tests) and choose one with --config. See multiple config files, and load secrets from a .env file as shown in environment variables with .env.


🎯 Override Config for One File or Test

Settings in the config are defaults. You can override use options for a file or a describe block with test.use():

import { test, expect } from '@playwright/test';

test.use({ viewport: { width: 390, height: 844 }, locale: 'hi-IN' });

test('mobile layout in Hindi locale', async ({ page }) => {
  await page.goto('/');
  // ...
});

And change the timeout of a single test with test.setTimeout(60_000) or test.slow().


📝 Assignment

  1. Set baseURL to https://www.saucedemo.com and update your login test to use page.goto('/').
  2. Change the reporter to show list output in the terminal and generate the HTML report.
  3. Enable screenshots and videos only for failed tests. Break a test on purpose and find the screenshot and video in the HTML report.
  4. Add a Mobile Chrome project using devices['Pixel 5'] and run only that project.
  5. Set retries: 1 locally, make a test fail, and observe the retry and the trace in the report.
  6. Bonus: set testIdAttribute: 'data-test' and replace one locator with page.getByTestId('login-button').

❓ FAQ

🤔 Where is the Playwright config file?

In the project root, named playwright.config.ts (or .js). Playwright finds it automatically; use --config path/to/file.ts to choose another.

🤔 How do I increase the timeout in Playwright?

Set timeout for whole tests and expect: { timeout } for assertions in the config, or call test.setTimeout() in a single test. See Playwright waits for all timeouts.

🤔 How do I run Playwright tests in headed mode by default?

Set use: { headless: false } in the config, or pass --headed on the command line.

🤔 What does workers mean in the Playwright config?

Workers are parallel processes that run tests. workers: 4 runs up to four test files at the same time; undefined lets Playwright use about half of your CPU cores.

🤔 What is the difference between use and projects?

use sets default browser and context options for all tests. Each project adds a name and its own use settings on top, and every test runs once per project.

🎬 Watch the full Playwright tutorial series on YouTube!

Subscribe to SqaToolsByDY • Practice on sqatools.in