Default Playwright Config File
Learn which Playwright config file is loaded by default, where it belongs, what it controls, and how to customize it for local and CI runs.
Playwright Test looks for playwright.config.ts or playwright.config.js in the current directory. To use another file, pass its path with --config (or -c). The configuration file centralizes test-runner settings and shared browser-context options.
What is the default Playwright config file?
The expected filenames are:
playwright.config.tsfor TypeScript projectsplaywright.config.jsfor JavaScript projects
Playwright searches for the file from the directory where the command is run. The test directory defaults to the configuration file’s directory. See the official Playwright configuration guide for the current version-specific behavior.
Selecting a different file
npx playwright test --config=playwright.ci.config.ts
# The short form is also supported
npx playwright test -c playwright.ci.config.ts
Use an explicit path when a repository has separate local, CI, browser-matrix, or staging configurations.
Minimal TypeScript configuration
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests',
});
Save this as playwright.config.ts in the project root, then run:
npx playwright test
Minimal JavaScript configuration
const { defineConfig } = require('@playwright/test');
module.exports = defineConfig({
testDir: './tests',
});
Save it as playwright.config.js. Do not keep both default filenames in the same directory unless you always select one with --config; otherwise, the chosen file can be unclear to maintainers.
How configuration is organized
Runner options belong at the top level. Browser-context settings shared by tests belong inside use. This separation keeps execution policy distinct from how each browser context is created.
| Area | Common options | Purpose |
|---|---|---|
| Discovery | testDir, testMatch, testIgnore |
Choose which files Playwright collects. |
| Execution | fullyParallel, workers, retries, timeout |
Control concurrency, retries, and time limits. |
| Diagnostics | reporter, use.trace, use.screenshot, use.video |
Control reports and failure artifacts. |
| Browser context | use.baseURL, use.viewport, use.storageState |
Set defaults inherited by tests. |
| Browser coverage | projects |
Run the same tests with different browsers, devices, or environments. |
| Application startup | webServer |
Start a local server and wait until it is ready. |
A complete baseline configuration
This is an example starting point. Adjust each choice to your repository, browser coverage, and CI capacity.
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: process.env.CI ? 'dot' : 'list',
use: {
baseURL: 'http://127.0.0.1:3000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
webServer: {
command: 'npm run start',
url: 'http://127.0.0.1:3000',
reuseExistingServer: !process.env.CI,
},
});
The official guide uses these settings to demonstrate full parallel execution, CI retries, worker limits, an HTML-style reporting choice, a base URL, first-retry traces, a Chromium project, and local server startup. They are examples rather than universal defaults.
Important defaults
- Test file matching: files matching
.*(test|spec).(js|ts|mjs)are discovered by default. - Test timeout: each test has a 30-second default timeout, including its fixtures and
beforeEachhooks. - Retries: failed tests are not retried unless you configure
retries. - Workers: the documented default is half the logical CPU cores; set a limit when CI resources are constrained.
- Reporter: the documented default is
dotin CI andlistotherwise. - Async expect timeout: the API reference documents 5,000 milliseconds as the default timeout for asynchronous
expectmatchers.
Verify defaults against the Playwright version installed in your lockfile because the documentation is continuously updated.
Common configuration options
Discovery and test timeouts
export default defineConfig({
testDir: './e2e',
testMatch: /.*\.e2e\.ts/,
testIgnore: '**/fixtures/**',
timeout: 45_000,
expect: {
timeout: 7_000,
},
});
Use testMatch when naming conventions must be strict. Keep timeout high enough for legitimate application work, but fix slow setup rather than masking it with an extreme value.
Retries and workers
export default defineConfig({
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 2 : undefined,
});
Retries help distinguish transient CI failures from persistent defects, but they can hide flaky tests and increase runtime. More workers reduce wall-clock time only when the machine, application, and test data can handle the parallel load.
Reporters and artifacts
export default defineConfig({
reporter: process.env.CI ? [['line'], ['html', { open: 'never' }]] : 'list',
use: {
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
video: 'on-first-retry',
},
});
Artifact settings affect disk usage and CI upload time. Enable the detail needed to diagnose failures, then avoid retaining large videos for every successful test run.
Base URL and webServer
export default defineConfig({
use: {
baseURL: 'http://127.0.0.1:3000',
},
webServer: {
command: 'npm run dev',
url: 'http://127.0.0.1:3000',
timeout: 120_000,
reuseExistingServer: !process.env.CI,
},
});
baseURL lets a test call page.goto('/login'). webServer starts an application and waits for its readiness URL. They are complementary: one resolves navigation URLs, while the other manages application startup.
Projects for browsers and environments
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'mobile-chrome',
use: { ...devices['Pixel 5'] },
},
],
});
Projects are the cleanest way to vary browser, device, base URL, retries, or timeout while reusing the same test files.
Using the configuration from tests
import { test, expect } from '@playwright/test';
test('home page loads', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveTitle(/Home/);
});
The fixture uses the configured baseURL, so the test can navigate with a relative path.
Configuration checklist
- Create exactly one default file,
playwright.config.tsorplaywright.config.js, at the project root. - Install
@playwright/testand browser binaries appropriate for the project. - Set
testDirif tests are not in the configuration directory. - Put shared browser settings under
use. - Use
projectsfor browser or environment matrices. - Add
webServeronly when Playwright must start the application. - Choose retries, workers, and artifact retention separately for local runs and CI.
- Use
npx playwright test --config path/to/filewhen selecting a non-default file.
Troubleshooting
“No tests found”
Cause: the command is running from the wrong directory, testDir points elsewhere, or filenames do not match the discovery pattern.
Fix: run from the directory containing the config, set an explicit testDir, or inspect testMatch and testIgnore.
Playwright ignores my config
Cause: the file has a non-default name or the command is started from another directory.
Fix: pass --config=/absolute/or/relative/path and confirm the command is using the intended package installation.
Relative URLs fail
Cause: baseURL is missing or is set under the wrong object.
Fix: place it inside use, for example use: { baseURL: 'http://127.0.0.1:3000' }.
The test times out before the page is ready
Cause: the application is slow, the readiness URL is wrong, or the default 30-second test timeout is too short for a legitimate operation.
Fix: verify webServer.url, inspect server logs, and adjust timeout deliberately. Do not use a larger timeout to conceal a server that never becomes ready.
CI runs out of memory or becomes unstable
Cause: too many workers, browser projects, videos, or traces run at once.
Fix: lower workers, split projects into jobs, and retain artifacts only for failures or retries.
Tests pass locally but fail in CI
Cause: different environment variables, browser projects, base URLs, startup timing, or available CPU.
Fix: define CI-specific retries, workers, and reporter settings; make the target URL explicit; and run the same project locally when reproducing the failure.
Performance, reliability, and cost considerations
- Parallelism: increase workers only when tests isolate data and the CI machine has enough CPU and memory.
- Startup: reuse an existing local server during development, but use a clean, deterministic startup in CI.
- Retries: use them as a diagnostic safety net, then fix recurring flakes instead of increasing the retry count.
- Artifacts: traces, screenshots, and videos improve diagnosis but consume storage and upload time.
- Configuration cost: Playwright configuration itself has no separate service charge; runtime cost comes from the machines, browsers, CI minutes, and any application services used by the tests.
Or skip the browser setup
If the goal is a rendered image or PDF rather than an end-to-end test, ScreenshotNeo provides a single HTTP request to capture a URL. Cookie and consent banners are accepted and removed before capture, along with more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and each response identifies the result with X-Page-Verdict and X-Billed headers.
See the ScreenshotNeo API documentation for all options.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const bytes = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', bytes);
ScreenshotNeo also includes an MCP server so Claude, Cursor, and other MCP clients can call take_screenshot, get_page_info, and capture_pdf. Every feature is available on every plan: 1,000 screenshots per month are free with no card, and paid plans start at $5 for 3,000 shots.
Create a free ScreenshotNeo account.
FAQ
What is the default Playwright config filename?
playwright.config.ts or playwright.config.js in the current directory.
Can I store the file in a subdirectory?
Yes. Pass its path with --config or -c.
Where does baseURL belong?
Inside the top-level use object, because it is a browser-context setting.
Does Playwright retry failed tests automatically?
No. The documented default is zero retries; configure retries when you need them.
Should I use webServer instead of baseURL?
No. webServer starts and waits for the application; baseURL resolves relative navigation URLs. They solve different problems.
What is the default test timeout?
Playwright documents a 30-second timeout per test, including fixtures and beforeEach hooks.


