CTCaliberTek
Course: Playwright with TypeScript: End to End · Lesson 7 of 9Log in to track your progress and earn a certificate when you finish the course.
Software Testing

Playwright Configuration, Projects, and Parallel Execution

Published September 2, 2026·Updated October 29, 2026·9 min read
Like SaveLog in to like, save, and track progress.

Introduction

The playwright.config.ts file controls how your whole suite runs: which browsers, how many tests in parallel, how failures are retried, and what gets recorded. This lesson walks through a practical configuration you can adapt to your project.

Prerequisites

  • A Playwright project
  • Basic understanding of environment variables

Step-by-Step Guide

Step 1: Start from a practical config

This configuration runs tests fully in parallel, retries failures only on CI, records a trace on the first retry, and runs across three browser engines through projects.

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 ? 2 : undefined,
  reporter: 'html',
  use: {
    baseURL: process.env.BASE_URL ?? 'https://demo.playwright.dev',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
  ],
});

Step 2: Understand parallelism

Test files run in parallel across workers. fullyParallel also runs tests inside a single file in parallel. Tests must not depend on each other or share mutable state for this to be safe. Limit workers if your app or test data cannot handle the load.

Step 3: Add mobile and custom projects

A project is a named configuration. Use device descriptors to emulate phones, or create projects that run different folders of tests.

projects: [
  { name: 'desktop-chrome', use: { ...devices['Desktop Chrome'] } },
  { name: 'mobile-chrome', use: { ...devices['Pixel 7'] } },
  { name: 'mobile-safari', use: { ...devices['iPhone 14'] } },
],

Step 4: Choose reporters

Use several reporters at once: a readable one for the console, HTML for people, and JUnit for CI tools that display test results.

reporter: [
  ['list'],
  ['html', { open: 'never' }],
  ['junit', { outputFile: 'results/junit.xml' }],
],

Step 5: Start your app before the tests

The webServer option launches your dev server and waits for it to respond before running tests, then shuts it down afterwards.

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

FAQs

Why retry only on CI?
Locally you want failures to show up immediately so you can fix them. On CI, a limited number of retries and a captured trace help you tell genuinely flaky tests from real bugs, but retries should not hide persistent problems.
How many workers should I use?
Playwright defaults to about half your CPU cores. On shared CI machines, set a fixed number such as 2 to avoid overloading them, and increase it only if tests stay stable.

Summary

A good config makes the suite fast, stable, and easy to diagnose: parallel by default, retries and traces on CI, projects for each browser or device, and a webServer entry so the app starts itself.

Related tutorials

Comments

Log in or create a free account to join the discussion.

  • No comments yet. Be the first to comment.