Playwright "webServer reuseExistingServer" - Port Conflict or Stale Server
Playwright’s webServer starts your app before tests. reuseExistingServer controls whether it reuses a server already on the port. Misconfigured, it either errors that the port is taken (reuse false) or runs tests against a stale server (reuse true).
What this error means
CI fails with "Error: http://localhost:3000 is already used" (Playwright would not start its own server and reuse was off), or tests pass against an old build because an existing server was reused instead of a fresh one.
Error: http://localhost:3000 is already used, make sure that nothing
is running on the port/url or set reuseExistingServer:true in config.Common causes
reuseExistingServer false but port occupied
With reuseExistingServer: false, Playwright insists on starting its own server. If something already listens on that port, it refuses and errors instead of reusing it.
reuseExistingServer true reuses a stale server
With reuse always on, a leftover dev server from a previous run (or a different build) is reused, so tests run against stale code and pass or fail misleadingly.
How to fix it
Reuse locally, start fresh in CI
Gate reuse on !process.env.CI so local dev reuses a running server but CI always boots a clean one.
// playwright.config.ts
export default defineConfig({
webServer: {
command: 'npm run preview',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
timeout: 120000,
},
});Free the port and use the readiness url
- Ensure no leftover process holds the port in CI (a dedicated job avoids this).
- Set
urlso Playwright waits for actual readiness, not a fixed sleep. - Use a unique port per job/shard if multiple runs share a runner.
How to prevent it
- Set
reuseExistingServer: !process.env.CI. - Wait on the
urlfor readiness instead of a sleep. - Use per-shard ports when runs can collide on a port.