PRACTICAL GUIDE / playwright monorepo architecture
Playwright Monorepo Architecture with Project Graphs, Shards, and Unified Reports
Structure Playwright in a monorepo with package-owned suites, project dependencies, balanced CI shards, complete blob artifacts, and one unified report.
In this guide10 sections
- Establish one repository-level execution contract
- Keep package ownership inside a root topology
- Model setup with project dependencies
- Separate the project matrix from the shard matrix
- Resolve one stable inventory before sharding
- Treat blob output as an interchange artifact
- Verify completeness before merging
- Normalize paths and environment identity
- Handle setup and shard failures operationally
- Support focused local work without fragmenting CI
What you will learn
- Establish one repository-level execution contract
- Keep package ownership inside a root topology
- Model setup with project dependencies
- Separate the project matrix from the shard matrix
A monorepo Playwright design succeeds when package teams can own scenarios independently while CI still executes one coherent inventory and publishes one trustworthy result. Separate package commands without a common project and artifact contract produce duplicated setup, inconsistent filters, and reports that cannot answer whether the repository passed.
Use projects to describe execution policy and dependencies, shards to distribute the resolved inventory, and blob artifacts to transport results. Keep these three axes separate. Their composition should be explicit at the root even when test code remains package-owned.
Establish one repository-level execution contract
Choose the command, configuration root, browser installation, environment inputs, and reporter policy that define an official run. Package scripts may offer focused developer shortcuts, but CI should not discover a different Playwright world in every workspace.
The Playwright projects guide defines a project as a logical group of tests using the same configuration and supports project dependencies for setup work. In a monorepo, project names become report and artifact identity, so keep them stable and meaningful.
Animated field map
Monorepo Execution and Reporting Flow
Package-owned suites enter one project graph, CI partitions the resolved inventory, blob artifacts preserve results, and a verified merge publishes repository quality.
01 / package suites
Package test suites
Teams own scenarios, fixtures, tags, and stable source locations.
02 / project graph
Project dependency graph
Root policy selects suites, browsers, setup nodes, and environments.
03 / shard matrix
CI shard matrix
Each job runs one unique partition of the same resolved inventory.
04 / blob artifacts
Blob result artifacts
Every shard retains results, traces, screenshots, and identity.
05 / quality report
Unified quality report
Completeness checks precede merge and repository-level publication.
Keep package ownership inside a root topology
Each product package should own its test directory, domain fixtures, test data contracts, and CODEOWNERS rules. The root owns project registration, shared timeouts, artifact policy, and supported browser or environment matrix. Shared fixture libraries belong in a test-support package with an explicit public API, not through relative imports across product internals.
A simple topology keeps generated evidence outside source packages:
apps/
storefront/e2e/
backoffice/e2e/
packages/
test-support/src/
playwright/
setup/
report/
playwright.config.ts
test-results/
blob-report/Use one resolved @playwright/test dependency and browser installation for the official run. Multiple runner copies can disagree about configuration or report format. Autonomous release trains may justify independent configs, but then define a higher-level reporting protocol rather than pretending those runs form one native project graph.
Model setup with project dependencies
Project dependencies make authentication or environment setup visible to reporters and traces. Consumer projects should depend only on the setup they require. Do not make every package wait for a global setup that provisions unrelated products.
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: '.',
fullyParallel: true,
outputDir: 'test-results',
reporter: process.env.CI ? [['blob']] : [['html', { open: 'never' }]],
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{
name: 'storefront-auth-setup',
testDir: 'playwright/setup',
testMatch: /storefront-auth\.setup\.ts/,
},
{
name: 'storefront-chromium',
testDir: 'apps/storefront/e2e',
dependencies: ['storefront-auth-setup'],
use: { ...devices['Desktop Chrome'] },
metadata: { owner: 'storefront' },
},
{
name: 'backoffice-chromium',
testDir: 'apps/backoffice/e2e',
use: { ...devices['Desktop Chrome'] },
metadata: { owner: 'backoffice' },
},
],
});Use names that remain stable when CI jobs move. Avoid embedding shard numbers in projects; the runner adds shard identity to result artifacts. If setup creates mutable shared state, make it idempotent and safe when multiple shard jobs execute the same dependency.
Separate the project matrix from the shard matrix
Projects answer what configuration a test runs under. Shards answer which portion of the selected inventory a machine executes. A browser-package-environment cross product can grow quickly, so include only combinations backed by product risk and ownership.
Do not create projects named shard-1, shard-2, and so on. That duplicates CI partitioning in source configuration and makes local runs confusing. Likewise, do not use CI shards to represent different browsers while calling them one partition; the resulting merged report hides missing configuration coverage.
When a package needs only one browser in pull requests and a broader matrix later, select projects at the command or workflow level. Keep the project definitions stable so report history and ownership do not change with pipeline tier.
Resolve one stable inventory before sharding
Every shard job must use the same revision, lockfile, generated files, configuration, project filters, grep filters, and shard total. Only the current shard index should differ. A package generated after partitioning or a conditional test directory can cause duplicate or missing execution.
With fullyParallel: true, Playwright can distribute individual tests more evenly. Without it, sharding uses file-level granularity, which may be preferable while files still share mutable setup. Enabling full parallelism is an architecture decision: first remove ordering assumptions, module-level mutable state, and shared accounts.
Use unique one-based indexes from the CI matrix:
npx playwright test \
--shard="${SHARD_INDEX}/${SHARD_TOTAL}" \
--reporter=blobKeep SHARD_TOTAL identical across jobs and record both values in job metadata. If the selected inventory is small, more shards can add setup cost without shortening the critical path. Choose the count from observed execution and environment capacity rather than package count.
Treat blob output as an interchange artifact
The Playwright reporters documentation describes blob reports as detailed test-run output designed for later report generation and shard merging. Upload each shard's entire blob directory under a unique CI artifact name. Do not publish separate HTML reports as the repository result.
Artifact upload must run after test failure unless the job is cancelled. The failing shard contains the errors, traces, and screenshots reviewers need. Use a retention policy appropriate for test data, and exclude authentication state or other secrets from broad artifact globs.
Do not edit or unzip blob files before merge. Keep source checkout and dependency context available to the merge job so locations and attachments resolve consistently.
Verify completeness before merging
A merge command cannot know that a CI job vanished unless the pipeline checks. Produce a small, non-sensitive shard manifest beside each blob artifact containing run ID, revision, shard index, shard total, project filter, and command identity. The merge job must see every expected index exactly once and reject revision or filter mismatches.
This check prevents a dangerous outcome: three available artifacts merge successfully even though the fourth shard never uploaded. The HTML can look complete while silently omitting coverage. Missing evidence is a pipeline failure, regardless of whether available test results are green.
After verification, place blobs in one directory and run:
npx playwright merge-reports --reporter=html ./all-blob-reportsPublish the merged report only after the completeness gate. Preserve the raw blobs long enough to regenerate a different supported reporter without rerunning tests.
Normalize paths and environment identity
Shards should run from the same repository root with the same testDir. Different working directories can make source locations and snapshot paths inconsistent. When merging results from genuinely different operating systems, use an explicit merge configuration and tag those environments so the report does not imply identical render conditions.
Avoid absolute machine paths in custom attachments. Use testInfo.outputPath() for unique output owned by the test, and attach through the runner so the blob reporter captures it. Package fixtures should not write to one shared filename, because parallel workers and shards can overwrite it before upload.
Give test titles enough domain context to be useful when merged. Source path and project identity disambiguate duplicates technically, but a report full of tests named loads page forces reviewers to open every entry.
Handle setup and shard failures operationally
Disable fail-fast cancellation across shard jobs when the objective is complete regression evidence. A setup dependency failure should be visible as setup failure, with dependent tests not misreported as product passes. Upload setup traces from the shard where they ran.
The merge job should run when shard jobs fail, but not when the workflow is cancelled before artifacts are coherent. It should publish a failed unified report and return a failing status when any test or completeness check failed. Report publication is not the same as pipeline success.
When one package's environment is unavailable, do not remove its project from the inventory after the run begins. Mark the infrastructure failure explicitly. Dynamic omission converts an outage into apparently reduced scope without an accountable result.
Support focused local work without fragmenting CI
Developers need fast package commands. Provide wrappers that call the root config with --project, a source path, or a stable tag. These are views of the same graph, not alternate configurations with different fixture and reporter behavior.
Track ownership in project metadata, path conventions, or test annotations and surface it in custom reporting. Ownership should route failures, not decide whether results are merged. Repository quality still needs one index where a reviewer can filter by package, project, tag, and status.
Use this architecture checklist:
- Package teams own scenarios and fixtures while the root owns execution policy.
- Project nodes express real configurations and setup dependencies, never shards.
- Every shard resolves the same revision, inventory, filters, and shard total.
- Parallel mode is enabled only after tests and data are independent.
- Blob artifacts upload on failure and exclude authentication material.
- A manifest gate proves all expected shard outputs are present and compatible.
- One merged report preserves package, project, shard, source, and attachment identity.
Test the pipeline by forcing a failed scenario, a failed setup project, and a missing shard artifact. The monorepo design is complete when each case produces one honest report and a failing repository signal, while a normal run lets every package retain ownership without losing the system-wide view.
// LIVE COURSE / THE TESTING ACADEMY
Playwright Automation Mastery
Go beyond Selenium. Master Playwright with JS/TS in 90 days.
From the instructor behind this guide.
Playwright jobs are growing 8x faster than Selenium. 90 days / 75+ live hrs / Tue-Thu-Sat 7 AM IST.
PRIMARY REFERENCES
Verify the details at the source
QABattle guides are practical explanations. Product behavior, standards, and APIs can change, so use these primary references for the canonical details.
- 01Playwright documentation
Microsoft
Canonical API, locator, fixture, browser, and test-runner behavior.
- 02Playwright best practices
Microsoft
Official guidance for resilient tests, isolation, and user-facing locators.
- 03
FAQ / QUICK ANSWERS
Questions testers ask
Should every monorepo package have its own Playwright configuration?
Package configs can work for autonomous products, but one root config is stronger when suites share projects, setup dependencies, sharding, and report merging. Keep package ownership through test directories and metadata.
What is the difference between a Playwright project and a CI shard?
A project defines a logical test configuration and dependency node. A shard partitions the selected test inventory across machines; it should not encode browser, package, or environment policy.
Why use blob reports for Playwright monorepo shards?
Blob reports retain detailed results and attachments in a mergeable format. A downstream job can combine every shard into one HTML or other supported report without rerunning tests.
How can a merge job avoid publishing an incomplete green report?
Record the expected shard and project inventory, upload artifacts even after test failure, verify every expected blob is present, and mark missing artifacts as pipeline failure before publishing.
When should fullyParallel be enabled for monorepo sharding?
Enable it after tests are independent at test level. It improves shard balance, but it can expose file-local shared state and ordering assumptions that file-level distribution previously hid.
RELATED GUIDES
Continue the learning route
GUIDE 01
Shard Playwright Tests and Merge Reports Across CI Jobs
Split Playwright tests across balanced CI shards, preserve blob artifacts, and merge every job into one trustworthy HTML report with attachments.
GUIDE 02
Playwright Project Dependencies for Observable Setup and Teardown
Use Playwright project dependencies for visible, traceable setup and teardown with explicit prerequisites, artifacts, filtering, and cleanup.
GUIDE 03
Design a Playwright Project Matrix for Browsers, Devices, and Environments
Build a focused Playwright project matrix for browsers, mobile devices, and environments without multiplying runtime or obscuring failures.
GUIDE 04
Harden Playwright CI with Pinned Containers, Browser Caches, and Artifacts
Build reproducible Playwright CI with matching pinned containers, measured browser-cache policy, stable workers, and failure artifacts that survive.