all posts

The best platforms for running Playwright tests in 2026

Ajay Kumar··8 min read

Playwright is fast. Playwright suites in CI are frequently not, and the reason is almost never the framework — it's that a browser test needs a real browser, a real browser needs real memory, and the default CI runner has two cores and a fixed amount of both.

Four different kinds of platform solve this, and they solve genuinely different problems. Picking by price rather than by problem is how teams end up paying for a cross-browser grid to fix a parallelism issue. I build PandaStack, which is one of the four; I'll flag where it applies.

First, work out which problem you have

Three distinct complaints get described as 'our Playwright tests are slow', and they have different fixes.

  • Wall-clock time — the suite is fine, there's just a lot of it, and it runs too serially. This is a parallelism problem.
  • Flakiness — tests pass locally and fail intermittently in CI. This is usually a resource problem masquerading as a timing problem.
  • Coverage — you need Safari, or an older Chrome, or a real device. This is a browser-matrix problem, and it's the only one where a commercial grid is the obvious answer.

The flakiness case is worth dwelling on because it's so often misdiagnosed. A browser that's short on memory gets slow; a slow browser misses timeouts; a missed timeout looks exactly like a race condition in your test. Teams add retries and waits, the suite gets slower, and the underlying cause — four workers sharing 4 GB — is never addressed.

# The tell: raise the resources, and the "race condition" disappears
# Chromium wants roughly 1GB per worker under real page loads.

# What the runner actually has
free -h && nproc

The four options

1. Your existing CI, sharded

Playwright shards natively, and CI providers run matrix jobs. Before buying anything, try splitting the suite across parallel jobs — it's a few lines of config and it's often enough.

jobs:
  test:
    strategy:
      matrix:
        shard: [1, 2, 3, 4]
    steps:
      - run: npx playwright test --shard=${{ matrix.shard }}/4

This is the right first move, and its ceiling is real: you pay per runner-minute, cold browser installation happens on every job unless you cache it well, and merging reports across shards is fiddly. But it costs an afternoon to try, and an afternoon is cheaper than a procurement decision.

2. A commercial browser grid

BrowserStack, Sauce Labs, LambdaTest. You point Playwright at their endpoint and your tests run on their browsers.

What you're buying is the matrix: real Safari on real macOS, older browser versions, actual mobile devices. If your requirement is genuinely cross-browser coverage, this is the category and the alternatives don't compare.

What you're paying is per-parallel-session pricing, which gets expensive quickly, and network latency on every single command — a remote grid turns each click into a round trip, and a test that runs in ten seconds locally can take considerably longer against a distant endpoint.

3. A hosted browser service

Browserbase, Steel, and similar. These give you browser instances over CDP, and they're built primarily for AI agents and scraping rather than for test suites.

They work for Playwright — you connect over CDP rather than launching locally — and they're good at the things agents need: session persistence, proxy rotation, captcha handling, live session viewing. For a test suite specifically, you're paying for features you don't use and you still have the round-trip latency of a remote browser.

Worth considering if you're already using one for a product feature and want to consolidate. Rarely the right choice if tests are the only use case.

4. Run browsers on your own compute, in parallel

The fourth option is to keep the browsers local to the test process and just get more machines. Each shard runs on its own VM with its own browsers, so there's no network round trip per command, and parallelism is bounded by what you're willing to spend rather than by a session limit.

This is my category. On PandaStack the shape is a sandbox per shard, created from the browser template, running its own Playwright process:

from concurrent.futures import ThreadPoolExecutor
from pandastack import Sandbox

SHARDS = 8

def run_shard(i: int) -> str:
    with Sandbox.create(template="browser", ttl_seconds=1800) as sb:
        sb.filesystem.upload("./repo.tar.gz", "/workspace/repo.tar.gz")
        sb.exec("cd /workspace && tar xzf repo.tar.gz && npm ci")
        res = sb.exec(f"cd /workspace && npx playwright test --shard={i}/{SHARDS}")
        sb.filesystem.download("/workspace/results.json", f"./results-{i}.json")
        return res.stdout

with ThreadPoolExecutor(max_workers=SHARDS) as pool:
    for out in pool.map(run_shard, range(1, SHARDS + 1)):
        print(out)

The trade-offs are honest ones. You get no cross-browser matrix — these are the browsers you install, which in practice means Chromium and Firefox, and Safari is not available on Linux at all. You own the environment, which means you also own keeping it current. In exchange you get browsers that are local to the test process, parallelism limited by budget rather than by a licence, and the ability to snapshot a browser mid-session and fork it, which is a genuinely different capability rather than a cheaper version of the same one.

Isolation matters more here than people expect. Browser tests leave state behind — profiles, downloads, service workers, cached credentials — and a shared runner leaks that between shards. A fresh VM per shard makes cross-contamination structurally impossible rather than something your teardown has to remember.

The cost comparison nobody does properly

Compare against the same workload, not the sticker price. Take one real suite run — say 400 tests, 8 shards, 6 minutes each — and price it four ways: CI runner-minutes at your provider's rate, per-parallel-session on a grid, per-browser-minute on a hosted service, and per-second compute on your own VMs.

Then multiply by runs per day, which is the number that actually decides this. A team merging forty times a day has a completely different answer from one that runs the suite nightly, and the crossover between 'CI is fine' and 'buy something' sits somewhere in between.

The shortlist

  • Sharded CI — start here. Free to try, often sufficient, and it tells you what your actual parallelism ceiling is.
  • BrowserStack / Sauce Labs / LambdaTest — buy when you need real Safari, old browsers, or real devices. Not a parallelism fix.
  • Browserbase / Steel — sensible if you already run one for a product feature; overkill for tests alone.
  • Self-hosted Selenium Grid — cheapest at high volume if you already run Kubernetes and have someone to maintain it.
  • PandaStack — a VM per shard with local browsers, per-second billing, and snapshot/fork of browser sessions. Chromium and Firefox only; no Safari.

The short version

Diagnose before you buy. If the suite is flaky, give it more memory before you give it retries. If it's slow, shard it in the CI you already pay for. If you genuinely need Safari and real devices, a commercial grid is the answer and nothing else comes close. And if what you need is many browsers in parallel with no per-command latency, run them on your own compute — which is a bigger step than a config change and a smaller one than it looks.

Frequently asked questions

Why are my Playwright tests flaky in CI but not locally?

Most often because the CI runner has far less memory than your laptop, and Chromium under a real page load wants roughly a gigabyte per worker. Starved of memory, the browser gets slow, slow browsers miss the timeouts your tests assume, and a missed timeout is indistinguishable from a race condition in the test. Teams then add retries and explicit waits, which makes the suite slower without touching the cause. Check the runner's actual memory and core count first, reduce workers to fit or move to a larger machine, and see how much of the flakiness disappears before changing any test code.

Is a browser grid faster than running browsers locally?

Usually not, and often meaningfully slower per test. A remote grid turns every Playwright command — every click, every selector query, every assertion — into a network round trip, so a test with hundreds of interactions accumulates latency that simply does not exist when the browser runs beside the test process. What a grid buys you is coverage: real Safari on real macOS, older browser versions, actual mobile devices, none of which you can reproduce on a Linux VM. Buy a grid for the matrix, not for speed.

How many shards should I split a Playwright suite into?

Enough that the slowest shard sets an acceptable wall-clock time, and no more — each shard pays a fixed startup cost for installing dependencies and browsers, so past a certain point you are adding overhead rather than removing it. A practical approach is to start at four, measure, and double until the improvement flattens. Watch the slowest shard rather than the average, since uneven test durations mean one long-running spec can dominate. If startup cost is what dominates, cache the browser installation or start from an image that already has it.

Can I run Safari tests on Linux?

No. WebKit builds run on Linux and Playwright supports them, but that is not the same engine and browser combination that ships on macOS and iOS, and the differences show up in exactly the rendering and behaviour cases you wanted Safari coverage for. If real Safari is a requirement, you need macOS hardware — either a commercial grid that provides it, or your own Mac runners. This is the single clearest reason to pay for a commercial browser grid, and it is worth being precise about whether you need real Safari or merely a second rendering engine.

Should each test shard get its own isolated environment?

Yes, and browser tests make the case more strongly than most workloads. Browsers leave state behind — user profiles, downloads, service workers, local storage, cached credentials — and shards sharing a runner can leak that state between them, producing failures that depend on execution order and are extremely difficult to reproduce. A fresh environment per shard makes contamination structurally impossible instead of relying on teardown code to be complete. It also means a browser that hangs or crashes takes down one shard rather than corrupting the rest of the run.

Keep reading

Run code in a microVM in one API call.

49ms p50 cold start. Fork, snapshot, and scale to zero.

Start free
Written by Ajay Kumar, Founder, PandaStack.