1. Introduction: Why Monorepos Need a Scalable Playwright Test Setup
Modern organizations rarely have a single frontend application.
A product platform may contain:
Customer Portal
Admin Portal
Partner Portal
Internal Dashboard
Shared Design System
Keeping all these applications in separate repositories can create duplicated test utilities, inconsistent Playwright versions, repeated fixtures, and difficult framework maintenance.
A Playwright monorepo test setup provides another approach.
A monorepo can keep application-specific tests isolated while sharing:
- Page Objects
- Fixtures
- API clients
- Test data
- Authentication helpers
- Environment utilities
- Reporting utilities
- Playwright configuration conventions
The architecture becomes:
Playwright Monorepo
|
+——————+——————+
| | |
Customer Portal Admin Portal Partner Portal
| | |
Tests Tests Tests
| | |
+——————+——————+
|
Shared Test Packages
|
+—————–+—————–+
| | |
Fixtures Utilities API
| | |
+—————–+—————–+
|
CI/CD
This approach is especially useful when multiple teams own related applications but need a consistent Playwright Automation Framework.
Playwright itself supports projects for different browsers, devices, environments, or logical test groups, making its test runner suitable for multi-application configurations.
2. What Is a Playwright Monorepo Test Setup?
A Playwright monorepo test setup is an automation architecture where multiple applications, test suites, and reusable testing packages are maintained inside one repository.
For example:
playwright-monorepo/
├── apps/
│ ├── customer-portal/
│ ├── admin-portal/
│ └── partner-portal/
├── packages/
│ ├── fixtures/
│ ├── utils/
│ ├── api/
│ └── test-data/
├── playwright.config.ts
├── package.json
└── pnpm-workspace.yaml
The important distinction is shared infrastructure without shared test ownership.
The customer portal should not accidentally execute admin tests.
Instead:
customer-portal
↓
customer tests
↓
shared fixtures/utilities
admin-portal
↓
admin tests
↓
shared fixtures/utilities
This creates separation at the application level while preserving reuse at the framework level.
3. Monorepo vs Single-Repository Playwright Architecture
| Area | Single application | Playwright monorepo |
| Applications | One | Multiple |
| Test ownership | Simple | Package/application based |
| Shared utilities | Local | Shared packages |
| CI | Simple | Selective/affected execution |
| Dependency management | Easy | Workspace-based |
| Reporting | One suite | Aggregated or package-specific |
| Scalability | Moderate | High |
| Initial setup | Easier | More complex |
A monorepo is not automatically better.
It becomes valuable when applications have meaningful relationships and teams benefit from shared infrastructure.
If you have one small application with 50 tests, a monorepo can add unnecessary complexity.
If you have five applications with thousands of tests and common authentication, API, data, and reporting needs, a Playwright TypeScript monorepo setup can significantly reduce duplication.
4. When Should Teams Use a Playwright Monorepo?
Consider a monorepo when:
- Multiple applications share the same organization.
- Applications use the same technology stack.
- Tests share authentication infrastructure.
- Teams need common fixtures.
- APIs are shared.
- CI pipelines need coordinated releases.
- You maintain a shared design system.
- Test utilities are duplicated across repositories.
- Multiple teams need consistent Playwright versions.
Avoid forcing unrelated applications into the same test repository.
A good architecture follows:
Share infrastructure, not application-specific assumptions.
5. Playwright Monorepo Prerequisites and Project Setup
You need:
- Node.js
- TypeScript
- Playwright
- npm, pnpm, or Yarn
- A workspace-capable package manager
- Git
- CI/CD platform
For a new Playwright project:
npm init playwright@latest
Playwright’s current installer supports TypeScript and can create configuration, tests, browser binaries, and optional CI workflow files.
For a larger organization, pnpm is a common workspace choice because it provides explicit workspace configuration and efficient dependency management.
6. Creating a Playwright Monorepo Folder Structure
A practical enterprise structure is:
playwright-monorepo/
│
├── apps/
│ ├── customer-portal/
│ │ ├── tests/
│ │ ├── pages/
│ │ ├── test-data/
│ │ ├── playwright.config.ts
│ │ └── package.json
│ │
│ ├── admin-portal/
│ │ ├── tests/
│ │ ├── pages/
│ │ ├── test-data/
│ │ ├── playwright.config.ts
│ │ └── package.json
│ │
│ └── partner-portal/
│ ├── tests/
│ ├── pages/
│ └── playwright.config.ts
│
├── packages/
│ ├── fixtures/
│ ├── utils/
│ ├── api/
│ ├── test-data/
│ └── auth/
│
├── playwright.config.ts
├── package.json
├── pnpm-workspace.yaml
└── tsconfig.json
Responsibilities
| Directory | Responsibility |
| apps/ | Application-specific tests |
| pages/ | Application-specific Page Objects |
| fixtures/ | Shared Playwright fixtures |
| utils/ | Generic utilities |
| api/ | Reusable API clients |
| test-data/ | Shared data builders |
| auth/ | Authentication helpers |
| reports/ | Generated artifacts |
This separation prevents a common enterprise problem: putting everything into one enormous tests/ directory.
7. Configuring pnpm Workspaces
At the repository root:
# pnpm-workspace.yaml
packages:
– ‘apps/*’
– ‘packages/*’
Root package.json:
{
“name”: “playwright-monorepo”,
“private”: true,
“scripts”: {
“test”: “playwright test”,
“test:customer”: “pnpm –filter customer-portal test”,
“test:admin”: “pnpm –filter admin-portal test”,
“test:all”: “pnpm -r test”
},
“devDependencies”: {
“@playwright/test”: “^1.60.0”,
“typescript”: “^5.0.0”
}
}
An application package can declare:
{
“name”: “customer-portal”,
“private”: true,
“scripts”: {
“test”: “playwright test”
},
“dependencies”: {
“@company/test-fixtures”: “workspace:*”
}
}
The important architectural principle is that shared packages should expose stable interfaces.
For example:
packages/fixtures
↓
authenticatedPage()
apiClient()
testUser()
The customer application consumes those capabilities without knowing how they are internally implemented.
8. Creating Separate Playwright Projects for Multiple Applications
Playwright projects are logical groups of tests with shared configuration. They can represent browsers, environments, devices, or test groups.
A root configuration can orchestrate applications:
// playwright.config.ts
import { defineConfig } from ‘@playwright/test’;
export default defineConfig({
fullyParallel: true,
reporter: [
[‘list’],
[‘html’, {
outputFolder: ‘reports/root’
}]
],
projects: [
{
name: ‘customer’,
testDir: ‘./apps/customer-portal/tests’,
use: {
baseURL:
process.env.CUSTOMER_URL ??
‘http://localhost:3001’
}
},
{
name: ‘admin’,
testDir: ‘./apps/admin-portal/tests’,
use: {
baseURL:
process.env.ADMIN_URL ??
‘http://localhost:3002’
}
},
{
name: ‘partner’,
testDir: ‘./apps/partner-portal/tests’,
use: {
baseURL:
process.env.PARTNER_URL ??
‘http://localhost:3003’
}
}
]
});
Run one application:
npx playwright test –project=customer
Run everything:
npx playwright test
Playwright’s –project option allows teams to select individual projects instead of running every configured project.
9. Shared Page Objects in a Playwright Monorepo
Not every Page Object belongs in packages/.
A useful rule is:
Generic/shared page → packages/
Application-specific page → apps/<app>/pages/
For example:
// packages/utils/src/navigation.ts
import { Page } from ‘@playwright/test’;
export class Navigation {
constructor(
private readonly page: Page
) {}
async openProfile() {
await this.page
.getByRole(‘link’, {
name: ‘Profile’
})
.click();
}
}
Application-specific Page Object:
// apps/customer-portal/pages/customer-home.page.ts
import { Page } from ‘@playwright/test’;
export class CustomerHomePage {
constructor(
private readonly page: Page
) {}
async openOrders() {
await this.page
.getByRole(‘link’, {
name: ‘Orders’
})
.click();
}
}
This prevents Page Objects from becoming overly generic.
10. Shared Playwright Fixtures Across Applications
Shared fixtures are one of the biggest benefits of a Playwright monorepo testing framework.
Example:
// packages/fixtures/src/base.ts
import {
test as base,
expect
} from ‘@playwright/test’;
type Fixtures = {
testUser: {
email: string;
role: string;
};
};
export const test =
base.extend<Fixtures>({
testUser: async ({}, use) => {
await use({
email:
‘automation@example.com’,
role: ‘customer’
});
}
});
export { expect };
Then:
import {
test,
expect
} from ‘@company/test-fixtures’;
test(‘customer profile’, async ({
page,
testUser
}) => {
await page.goto(‘/profile’);
await expect(
page.getByText(testUser.email)
).toBeVisible();
});
The fixture becomes a reusable contract.
Application tests don’t need to recreate the same user object.
11. Authentication and Storage State Across Monorepo Projects
Authentication is often shared across applications.
Playwright supports storageState for pre-authenticated browser contexts.
A setup project can create authentication state:
// apps/customer-portal/tests/auth.setup.ts
import {
test as setup,
expect
} from ‘@playwright/test’;
setup(
‘authenticate customer’,
async ({ page }) => {
await page.goto(‘/login’);
await page.getByLabel(‘Email’)
.fill(
process.env.CUSTOMER_USER!
);
await page.getByLabel(‘Password’)
.fill(
process.env.CUSTOMER_PASSWORD!
);
await page.getByRole(‘button’, {
name: ‘Sign in’
}).click();
await expect(
page.getByText(‘Dashboard’)
).toBeVisible();
await page.context()
.storageState({
path:
‘playwright/.auth/customer.json’
});
}
);
Then configure:
{
name: ‘customer-authenticated’,
testDir:
‘./apps/customer-portal/tests’,
use: {
baseURL:
process.env.CUSTOMER_URL,
storageState:
‘playwright/.auth/customer.json’
}
}
For larger frameworks, use project dependencies for setup workflows. Playwright recommends project dependencies over a traditional globalSetup approach because dependencies integrate with reporting, tracing, fixtures, retries, and normal project behavior.
12. Project Dependencies for Monorepo Setup
A useful architecture is:
Customer Auth Setup
|
v
Customer Chromium
Customer Firefox
Configuration:
projects: [
{
name: ‘customer-auth’,
testMatch:
/customer\.auth\.setup\.ts/
},
{
name: ‘customer-chromium’,
testDir:
‘./apps/customer-portal/tests’,
use: {
browserName: ‘chromium’,
baseURL:
process.env.CUSTOMER_URL,
storageState:
‘playwright/.auth/customer.json’
},
dependencies: [
‘customer-auth’
]
}
]
The dependency runs first, then dependent projects can execute. Playwright also supports teardown projects for cleanup workflows.
13. Environment and Configuration Management
Never hard-code environment-specific URLs throughout tests.
Use:
export const environment = {
customerUrl:
process.env.CUSTOMER_URL ??
‘http://localhost:3001’,
adminUrl:
process.env.ADMIN_URL ??
‘http://localhost:3002’,
apiUrl:
process.env.API_URL ??
‘http://localhost:4000’
};
Then:
await page.goto(
`${environment.customerUrl}/orders`
);
A better architecture uses Playwright’s baseURL:
use: {
baseURL:
process.env.CUSTOMER_URL
}
Then:
await page.goto(‘/orders’);
Playwright supports baseURL specifically to allow relative navigation and centralize target environment configuration.
14. API and UI Testing Across Multiple Applications
Shared API clients can live in:
packages/api/
Example:
import {
APIRequestContext
} from ‘@playwright/test’;
export class UserApi {
constructor(
private readonly request:
APIRequestContext
) {}
async createUser(
email: string
) {
return this.request.post(
‘/users’,
{
data: { email }
}
);
}
}
Test:
test(‘created user appears in UI’,
async ({ page, request }) => {
const api = new UserApi(request);
await api.createUser(
‘qa@example.com’
);
await page.goto(‘/users’);
await expect(
page.getByText(
‘qa@example.com’
)
).toBeVisible();
}
);
This is a strong enterprise pattern:
API
↓
Create deterministic state
↓
UI
↓
Validate user behavior
It avoids unnecessarily creating test data through long UI workflows.
15. Test Data Management in a Playwright Monorepo
Shared test data should be reusable but configurable.
Example:
export function createUser(
overrides = {}
) {
return {
firstName: ‘Test’,
lastName: ‘User’,
email:
`qa-${Date.now()}@example.com`,
role: ‘customer’,
…overrides
};
}
Usage:
const admin =
createUser({
role: ‘admin’
});
For parallel execution, avoid fixed shared identifiers.
Bad:
test-user@example.com
Better:
test-user-workerIndex-{timestamp}
Or use server-generated IDs.
The objective is:
Worker 1 → isolated data
Worker 2 → isolated data
Worker 3 → isolated data
rather than:
Worker 1 ─┐
Worker 2 ─┼→ SAME DATABASE RECORD
Worker 3 ─┘
16. Parallel Execution and Test Isolation
Playwright supports worker processes for parallel test execution, and workers controls the maximum number of concurrent workers. fullyParallel can enable broader parallel execution.
Root configuration:
export default defineConfig({
fullyParallel: true,
workers:
process.env.CI
? 4
: undefined,
retries:
process.env.CI
? 2
: 0,
use: {
trace: ‘on-first-retry’
}
});
Parallel execution works well only when tests are isolated.
Avoid:
Test A modifies global user
Test B expects original user
Instead:
Test A → User A
Test B → User B
For large suites, test isolation is more important than simply increasing worker count.
17. Browser and Application Project Configuration
A monorepo can combine application and browser dimensions.
For example:
projects: [
{
name: ‘customer-chromium’,
testDir:
‘./apps/customer-portal/tests’,
use: {
browserName: ‘chromium’,
baseURL:
process.env.CUSTOMER_URL
}
},
{
name: ‘customer-firefox’,
testDir:
‘./apps/customer-portal/tests’,
use: {
browserName: ‘firefox’,
baseURL:
process.env.CUSTOMER_URL
}
},
{
name: ‘admin-chromium’,
testDir:
‘./apps/admin-portal/tests’,
use: {
browserName: ‘chromium’,
baseURL:
process.env.ADMIN_URL
}
}
]
Playwright projects are explicitly designed for running the same tests under different browsers, devices, environments, or configurations.
Run only customer Chromium:
npx playwright test \
–project=customer-chromium
18. Application-Specific Playwright Configuration
Large organizations may prefer separate configs rather than one massive root file.
For example:
apps/
├── customer-portal/
│ └── playwright.config.ts
└── admin-portal/
└── playwright.config.ts
Customer config:
import { defineConfig } from ‘@playwright/test’;
export default defineConfig({
testDir: ‘./tests’,
use: {
baseURL:
process.env.CUSTOMER_URL
},
reporter: [
[‘list’],
[‘html’, {
outputFolder:
‘reports/customer’
}]
]
});
Run:
npx playwright test \
–config=apps/customer-portal/playwright.config.ts
This is often preferable when application teams need independent ownership.
A centralized root config is preferable when the automation architecture is tightly standardized.
19. Multiple Web Servers in a Playwright Monorepo
A local monorepo may need:
Customer → localhost:3001
Admin → localhost:3002
API → localhost:4000
Playwright supports multiple webServer entries.
webServer: [
{
command:
‘pnpm –filter customer-portal dev’,
url:
‘http://localhost:3001’,
name:
‘Customer Portal’
},
{
command:
‘pnpm –filter admin-portal dev’,
url:
‘http://localhost:3002’,
name:
‘Admin Portal’
},
{
command:
‘pnpm –filter api dev’,
url:
‘http://localhost:4000’,
name:
‘API’
}
]
This makes local execution much closer to the CI architecture.
20. Reporting and Test Artifact Management
Reporting becomes more complicated in a monorepo.
You may have:
reports/
├── customer/
├── admin/
├── partner/
└── combined/
Playwright supports multiple reporters in one configuration.
Example:
reporter: [
[‘list’],
[‘html’, {
outputFolder:
‘reports/customer’
}],
[‘json’, {
outputFile:
‘reports/customer/results.json’
}]
]
Keep artifacts application-specific when teams need independent ownership.
For organization-wide dashboards, generate a standardized JSON format and aggregate it later.
21. Debugging Playwright Monorepo Tests
Debugging becomes easier when artifact paths contain project information.
Example:
outputDir:
`test-results/${process.env.APP_NAME ?? ‘unknown’}`
Configure:
use: {
screenshot: ‘only-on-failure’,
video: ‘on-first-retry’,
trace: ‘on-first-retry’
}
Then a failed test might produce:
test-results/
└── customer/
└── chromium/
└── login-test/
├── trace.zip
├── screenshot.png
└── video.webm
Playwright’s project configuration also provides project-specific output directories and ensures unique output locations for parallel test execution.
22. Playwright Monorepo CI/CD With GitHub Actions
A simple matrix can run application suites independently:
name: Playwright Monorepo Tests
on:
pull_request:
push:
branches:
– main
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
app:
– customer
– admin
– partner
steps:
– uses: actions/checkout@v6
– uses: actions/setup-node@v6
with:
node-version: lts/*
cache: pnpm
– uses: pnpm/action-setup@v4
with:
version: 10
– run: pnpm install –frozen-lockfile
– run: pnpm exec playwright install –with-deps chromium
– name: Run tests
run: pnpm test:${{ matrix.app }}
– name: Upload report
if: !cancelled()uses:actions/upload-artifact@v5with:name:playwright-{{ matrix.app }}
path: |
reports/
test-results/
This creates:
|
+—- Customer
|
+—- Admin
|
+—- Partner
Each job gets independent resources.
23. Running Only Affected Playwright Tests
This is one of the biggest advantages of a monorepo—but also one of the hardest problems.
Suppose a pull request changes:
apps/customer-portal/
There is little value in automatically running every partner test.
A mature CI system can determine:
Changed files
↓
Affected application
↓
Affected shared package?
↓
Test selection
Example:
apps/customer-portal/**
↓
customer tests
packages/api/**
↓
customer + admin + partner tests
Shared package changes should generally trigger dependent applications.
For example:
packages/fixtures/
|
+—- customer
+—- admin
+—- partner
The critical architectural task is maintaining dependency ownership.
Don’t simply assume that directory-based filtering is sufficient.
24. Real-World Enterprise Playwright Monorepo Project
Imagine a SaaS company with:
Customer Portal
Admin Console
Partner Portal
All three use:
OAuth
Shared design system
Common identity service
Architecture:
Monorepo
|
+————-+————-+
| | |
Customer Admin Partner
| | |
Tests Tests Tests
| | |
+————-+————-+
|
Shared Playwright
Infrastructure
|
+————–+————–+
| | |
Fixtures API Test Data
| | |
+————–+————–+
|
CI/CD
The teams own:
Customer team → customer tests
Admin team → admin tests
Partner team → partner tests
Platform team → shared packages
This creates clear boundaries.
25. Common Playwright Monorepo Setup Errors
| Error | Cause | Solution |
| Tests run twice | Root and package configs overlap | Define ownership clearly |
| Wrong application URL | Environment variable collision | Use project-specific config |
| Shared fixture breaks one app | Fixture assumes application-specific UI | Keep shared fixtures generic |
| CI runs everything | No affected-test strategy | Add dependency-aware filtering |
| Reports overwrite each other | Same output folder | Use project-specific paths |
| Auth state conflicts | Shared storage file | Create application/role-specific states |
| Parallel tests fail | Shared test data | Generate isolated data |
| Browser missing in CI | Browser not installed | Run Playwright browser install |
| Local app unavailable | Missing webServer | Configure server startup |
| Workspace package not found | Incorrect workspace dependency | Use workspace:* and install from root |
26. Playwright Monorepo Best Practices
1. Define ownership
Every application and shared package should have clear owners.
2. Keep application tests local
Don’t put customer-specific tests in a global shared package.
3. Share infrastructure
Share:
- Fixtures
- API clients
- Data builders
- Authentication utilities
- Generic helpers
4. Avoid over-sharing Page Objects
A Customer Portal page should not become a generic framework abstraction just because another application has a similarly named page.
5. Standardize configuration
Use common defaults:
timeouts
retries
traces
screenshots
reporters
workers
Then override only when necessary.
6. Isolate authentication
Use separate storage states for:
customer
admin
partner
7. Make test data parallel-safe
Never rely on one mutable shared record.
8. Use project dependencies carefully
They are useful for setup and teardown workflows and integrate with Playwright’s reporting and fixtures.
9. Keep reports separate
A failed admin test should not be hidden inside a huge organization-wide report.
10. Optimize CI
Use:
- Matrix jobs
- Affected-test detection
- Parallel workers
- Sharding for very large suites
11. Standardize versions
One Playwright version across the workspace reduces inconsistent browser behavior.
12. Treat shared packages as APIs
Breaking a fixture package can break hundreds of tests.
27. Playwright Monorepo Architecture Interview Questions
1. Why use a Playwright monorepo?
To manage multiple application test suites while sharing common automation infrastructure and dependencies.
2. Should all tests be in one Playwright configuration?
Not necessarily.
Centralized projects work well for standardized organizations. Separate application configs work better when teams require independent ownership.
3. What should be shared?
Good candidates include:
Fixtures
API clients
Data builders
Authentication utilities
Generic helpers
Reporting utilities
4. What should remain application-specific?
Usually:
Page Objects
Business workflows
Application test data
Application-specific assertions
Application configuration
5. How do you prevent test duplication?
Move reusable infrastructure into packages and keep application tests focused on business behavior.
6. How do you handle authentication?
Use dedicated setup projects and storageState, with separate states for different applications or roles.
7. How do you handle parallel execution?
Ensure each test has isolated browser state and independent test data. Configure workers based on CI resources.
8. How do you run one application?
Use:
npx playwright test \
–project=customer
or a workspace command such as:
pnpm test:customer
9. How do you handle reports?
Give each project its own output directory, then aggregate results only when organization-wide reporting is required.
10. What is the biggest monorepo risk?
Creating a shared framework so tightly coupled that a change for one application breaks every application.
The goal is controlled reuse, not maximum reuse.
28. Playwright Monorepo Learning Roadmap
Level 1: Playwright TypeScript
Learn:
- Locators
- Assertions
- Fixtures
- Projects
- Authentication
- Reporting
Level 2: Workspace Management
Learn:
- npm workspaces
- pnpm workspaces
- Yarn workspaces
- Package dependencies
- Workspace filtering
Level 3: Framework Architecture
Learn:
- Page Object Model
- Custom fixtures
- API utilities
- Test data builders
- Configuration layers
Level 4: Enterprise CI/CD
Learn:
- GitHub Actions
- Matrix execution
- Affected tests
- Parallel execution
- Test sharding
- Artifact management
Level 5: Automation Architecture
Learn:
- Ownership boundaries
- Shared package design
- Test isolation
- Dependency graphs
- Framework governance
- Reporting architecture
Related topics include Advanced Playwright Automation Techniques, Playwright Test Architecture for Large Projects, Playwright Multi-Tenant Testing Strategy, Playwright Custom Fixtures Advanced, Playwright Test Sharding Advanced, Playwright Network Mocking Advanced, Playwright Custom Reporter Development, Playwright Component Testing Advanced, Playwright Accessibility Testing Advanced, Playwright Performance Testing Techniques, Playwright Authentication Tutorial, Playwright API Testing, Playwright Page Object Model, Playwright Fixtures Tutorial, Playwright Parallel Execution Tutorial, Playwright Reporting Tutorial, Playwright CI/CD Tutorial, Playwright GitHub Actions Tutorial, Playwright Docker Tutorial, Playwright TypeScript Tutorial, Playwright Framework Design, Playwright Best Practices, and Playwright Interview Questions.
29. FAQs: Playwright Monorepo Test Setup
What is a Playwright monorepo test setup?
It is a repository architecture that manages multiple applications and their Playwright test suites while sharing reusable automation packages.
Can Playwright work in a monorepo?
Yes. Playwright’s project model can organize tests into logical groups, and workspace package managers can manage application-specific and shared dependencies.
How do I set up Playwright in a pnpm monorepo?
Create a root pnpm-workspace.yaml, place applications under apps/, shared testing libraries under packages/, and define Playwright configurations at either the root or application level.
Should each application have its own Playwright config?
It depends.
Use separate configs when applications have independent ownership and environments. Use one root config with projects when consistent centralized orchestration is more important.
How do I share Playwright fixtures across applications?
Create a workspace package such as:
packages/fixtures/
and import its exported fixtures from application-specific test suites.
How do I share Page Objects?
Only share Page Objects when the underlying UI and behavior are genuinely common. Application-specific Page Objects should remain within their application’s package.
How do I handle authentication?
Create authentication setup projects and save role/application-specific storage states. Playwright’s storageState can then initialize authenticated browser contexts.
How do I run only one application?
With centralized projects:
npx playwright test –project=customer
With workspace scripts:
pnpm test:customer
Can Playwright monorepos run tests in parallel?
Yes. Configure Playwright workers and parallel execution while ensuring test data and application state are isolated.
Can different applications use different browsers?
Yes. Playwright projects can represent different browsers, devices, environments, or application configurations.
Can a monorepo run multiple local applications?
Yes. Playwright’s webServer supports one or multiple development servers.
How should monorepo reports be organized?
Keep application-specific reports separate and aggregate them only when a central dashboard or organization-wide report is required.
