Web server
The webServer option in playwright.config.ts starts your dev server before any test runs and kills it after. The setting I always set: reuseExistingServer: !process.env.CI — locally it reuses my already-running 'npm run dev' so tests start instantly, on CI it always starts fresh.
Basic setup — start a dev server for all tests
I add webServer when writing tests against a local app that isn't deployed anywhere yet. Playwright waits for the url to return a 2xx/3xx response before running the first test. If the server doesn't respond within timeout milliseconds, tests fail with a clear error.
reuseExistingServer: !process.env.CI is the key setting. Locally: if my dev server is already running (which it usually is), Playwright just uses it without starting a new one — tests start in seconds. On CI: CI is set, so !process.env.CI is false, Playwright always starts fresh.
Slow server — increase timeout
The default timeout is 60 seconds. For Next.js or other frameworks that do a full build on first start, I bump this to 120 seconds. On CI with a slow runner it can take even longer.
Wait for server output instead of URL
Sometimes the URL check isn't the right signal — the server responds 200 before the database connection is ready. The wait option waits for a specific string in stdout or stderr instead. Named capture groups in the regex get stored as environment variables.
Multiple servers — frontend + backend
For projects where the frontend and backend run on different ports, I pass an array. Each server gets a name that prefixes its log output — makes it easy to see which server printed what in CI logs.
Pairing webServer with baseURL
I always pair webServer with baseURL in the use section. Without baseURL, every page.goto() needs the full URL. With it, I write page.goto('/orders') and Playwright prepends http://localhost:3000 automatically.