Power Your Software Testing
with AI and Cloud

Supercharge QA with AI for Faster & Smarter Software Testing

Next-Gen App & Browser Testing Cloud

How to Use Playwright Projects: A Detailed Guide

Learn what Playwright projects are, how to configure and run tests across browsers, environments, and use project dependencies for organized testing.

Published on: October 19, 2025

  • Share:

When running Playwright tests across different browsers, devices, and operating systems, the usual approach is to create separate configuration files for each scenario. That quickly turns into a repetitive setup and boilerplate code. However, Playwright projects solve this by letting you define everything in one place.

You can specify which browsers to use, which devices to emulate, and even pre-set authentication states, all in a single configuration file. Once that’s set up, your tests automatically run in the right environment without needing to duplicate code.

Overview

In Playwright, a project is a logical group of tests that share the same configuration, such as browser, device, or environment, allowing tests to run across various environments.

How to Configure Playwright Projects?

Playwright projects are defined in the playwright.config.ts file to run the same tests under different conditions. You can configure projects for:

  • Multiple Browsers: Each project sets browserName (e.g., Chromium, Firefox, WebKit) while inheriting defaults like headless mode or viewport. This allows isolating browser-specific behavior.
  • Multiple Environments: Each project sets environment-specific details, such as baseURL or authentication state. Tests automatically use the correct configuration without changing the test script.

How to Use Dependencies in Playwright Projects?

Playwright project dependencies allow one project to run only after another completes, enabling shared sessions, setup routines, or cleanup tasks. You can use dependencies for:

  • Running Projects in Sequence: Define dependencies in the project configuration so one project runs after another. For example, a setup-auth project logs in and saves a session, and authenticated-tests uses that session. This avoids repeating login steps and ensures a consistent test state.
  • Teardown and Cleanup: Create a project that runs after dependent projects to reset states or clean up test data. For example, a cleanup-db project can reset a database after main tests complete, centralizing teardown logic.
  • Filtering Tests by Project: Use testMatch in each project to run only relevant tests. For example, api-smoke tests run in the api-smoke project, and ui-regression tests run in the ui-regression project. This keeps test files clean and configurations organized.

What Are Playwright Projects?

Playwright projects allow you to define separate testing contexts within a single configuration file. Each one acts like an isolated environment that can extend or override shared settings, making it easier to manage variations in how your tests are run.

This becomes especially useful when your suite needs to support different browsers, environments, or user scenarios like language preferences, screen sizes, or authentication states.

In practical terms, the projects field inside your playwright.config.js (or .ts) file is simply an array, where each item represents a specific configuration. You can customize options such as the browser engine, viewport size, test filters, and more.

Example:

export default defineConfig({
 projects: [
   {
     name: 'chromium',
     use: { browserName: 'chromium' },
   },
   {
     name: 'firefox',
     use: { browserName: 'firefox' },
   },
   {
     name: 'webkit',
     use: { browserName: 'webkit' },
   },
 ],
});

With this environment in place, Playwright will automatically execute your tests once per project, in this case, once per browser. There’s no need to duplicate your test files or write custom scripts for each platform. The framework takes care of sequencing and also integrates with Playwright reporting capabilities.

But browser variation is just one use case. You can also define projects to represent:

  • Different application environments (like staging and production).
  • Logged-in vs. guest user flows.
  • Desktop and mobile configurations.
  • Projects using different environment variables or headers.

New to Playwright? Refer to this complete Playwright tutorial.

How to Configure Projects in Playwright?

You can configure Playwright projects in the playwright.config.ts file, let tests run across browsers by setting browserName and defaults, and across environments by setting baseURL or auth, auto-applying configs without changing tests.

Below, we’ll look at how to configure Playwright projects for handling different browsers and another to switch between environments.

For Multiple Browsers

Cross browser testing is critical to ensure your application behaves as expected for all users, no matter what browser they choose. Playwright projects let you declare a separate configuration for each browser in a clean and maintainable way by using the browserName setting.

Here’s an example that illustrates how to set it up:

export default defineConfig({
 use: {
   headless: true,
   viewport: { width: 1280, height: 720 },
 },
 projects: [
   {
     name: 'Chrome',
     use: { browserName: 'chromium' },
   },
   {
     name: 'Firefox',
     use: { browserName: 'firefox' },
   },
   {
     name: 'WebKit',
     use: { browserName: 'webkit' },
   },
 ],
});

LambdaTest Playwright Projects GitHub Repository

The default settings, like running tests in Playwright headless mode and setting a common viewport, apply to all projects. Each project then overrides only what it needs: in this case, the browser engine.

This approach makes it easy to isolate and troubleshoot browser-specific behavior, which is especially helpful when working in CI environments or reproducing bugs locally.

For Multiple Environments

Another use case for Playwright projects is managing test execution across different environments, such as development, staging, and production. Instead of adding if conditions inside your test files to switch behaviors, you can assign environment-specific details directly in each project’s config.

Here’s how you might structure your configuration:

export default defineConfig({
   projects: [
     {
       name: 'dev',
       use: {
         baseURL: 'https://dev.myapp.com',
         storageState: 'auth/dev.json',
       },
     },
     {
       name: 'staging',
       use: {
         baseURL: 'https://staging.myapp.com',
         storageState: 'auth/staging.json',
       },
     },
   ],
 }); 

With this structure, you can keep your test code environment-agnostic. Instead of hardcoding URLs, you write await page.goto('/dashboard'). And Playwright will automatically prefix the correct baseURL according to the active project.

If you need dynamic control, use environment variables:

import { defineConfig } from '@playwright/test';


export default defineConfig({
 use: {
   baseURL: process.env.ENV_URL,
 },
});

However, defining your environments via projects is often a better long-term approach; it improves reproducibility, avoids external dependencies, and keeps your test environment more consistent across runs.

Note

Note: Run Playwright tests across 50+ browser environments. Try LambdaTest Now!

How to Run Tests Using Playwright Projects?

Playwright runs tests per project with specific browsers or environments. You can run all projects or a single one, skip tests conditionally, organize by folders, and execute in parallel or on the cloud.

For Multiple Browsers

When you're running the same test suite on multiple browsers, Playwright will execute each test once per browser-specific project. This helps catch inconsistencies early, for example, rendering differences or unsupported features, without needing to duplicate test logic.

Take this example configuration:

export default defineConfig({
 use: {
   headless: true,
   viewport: { width: 1280, height: 720 },
 },


 projects: [
   {
     name: 'Chromium',
     use: {
       browserName: 'chromium',
     },
   },
   {
     name: 'Firefox',
     use: {
       browserName: 'firefox',
     },
   },
 ],
});

Now consider a simple test file:

import { test, expect } from '@playwright/test';
test('should load homepage', async ({ page }) => {
 await page.goto('https://ecommerce-playground.lambdatest.io/index.php?route=account/register');
 await expect(page).toHaveTitle("Register Account");
});

To run the test in each browser, execute the following command:

npx playwright test

You’ll see results grouped by project name in the terminal, which makes it easier to identify browser-specific issues.test execution for each-browser

To narrow your test run to a single browser, execute the command below:

npx playwright test --project=Chromium

If a test should only apply to one browser, such as a feature exclusive to Chromium, you can add a condition directly in the test definition. This gives you the flexibility to adapt to browser-specific behaviors without duplicating your test files.

test('feature only on Chromium', async ({ page, browserName }) => {
   test.skip(browserName !== 'chromium', 'Only runs on Chromium');
   await page.goto('https://ecommerce-playground.lambdatest.io/index.php?route=account/register');
   await expect(page).toHaveTitle("Register Account");
});

Run the command below to execute the test only on Chromium and skip Firefox:

npx playwright test
test execution skipping firefox

For Multiple Environments

The same principles apply when running tests in different environments, like staging, test, or production. Rather than manually switching URLs or modifying test files, you can define those contexts as distinct projects.

Here is an example configuration:

export default defineConfig({
 use: {
   headless: true,
   viewport: { width: 1280, height: 720 },
 },


 projects: [
   {
     name: 'staging',
     use: {
       baseURL: 'https://www.lambdatest.com/?env=staging',
     },
   },
   {
     name: 'production',
     use: {
       baseURL: 'https://www.lambdatest.com/?env=production',
     },
   },
 ],
});

And here’s a generic test that works for both:

test('homepage loads', async ({ page }) => {
 await page.goto('/selenium-playground');
 await expect(page).toHaveTitle('Selenium Grid Online | Run Selenium Test On Cloud');
});

Run the command below to execute the test once in each browser:

npx playwright test

You’ll see these test results.test execution once in each browser

Playwright uses the active project's baseURL to resolve relative paths automatically. The same code executes in both environments, no extra conditionals needed.

To run tests in production only, execute the following command:

npx playwright test --project=production

Now, you’ll see these test results.test execution on production

If a specific test should only run in one environment, you can add logic like this:

test('beta feature visible', async ({ page }, testInfo) => {
 test.skip(testInfo.project.name !== 'staging', 'Feature not yet live in production');
 await page.goto('/selenium-playground');
 await expect(page).toHaveTitle('Selenium Grid Online | Run Selenium Test On Cloud');
});

Again, this keeps your suite clean and maintainable while still adapting to the realities of multi-environment testing.

Run the command below to execute the test only on staging and skip production:

npx playwright test
test execution on staging skipping production

As your test suite grows, running everything locally may become impractical. That’s where cloud platforms come into play. Among others, platforms like LambdaTest provide infrastructure for scalable, parallel execution across a wide range of browsers and devices, all compatible with Playwright.

With LambdaTest, you can run automated tests on its Playwright automation cloud across various browser and operating system combinations.

To get started, check out this guide on Playwright testing with LambdaTest.

...

Splitting Tests Into Projects

When your test suite grows in size and complexity, organizing your tests into groups becomes essential. Instead of letting everything run together, you can structure tests by their purpose.

For instance, smoke checks, regression coverage, or admin-specific flows. Playwright Projects allow you to do this cleanly by defining targeted scopes based on file patterns.

Let’s consider that you have the following structure in your project:

tests/
├── smoke/
│   └── homepage.spec.js
├── regression/
│   └── checkout.spec.js
└── admin/
    └── user-management.spec.js

You can map each of these folders to a specific project in your configuration:

export default defineConfig({
 projects: [
   {
     name: 'Smoke Tests',
     testMatch: /.*/smoke/.*.spec.js/,
   },
   {
     name: 'Regression Tests',
     testMatch: /.*/regression/.*.spec.js/,
   },
   {
     name: 'Admin Panel',
     testMatch: /.*/admin/.*.spec.js/,
   },
 ],
});

Here’s how each project works:

  • Smoke Tests will run only the quick checks inside the smoke folder.
  • Regression Tests focus on the regression directory, which might include broader feature validation.
  • Admin Panel tests are scoped to administrative workflows and use a predefined login state for authenticated access.

Considering that the code in the three files is the same as shown below:

import { test, expect } from '@playwright/test';
test('should load homepage', async ({ page }) => {
 await page.goto('https://ecommerce-playground.lambdatest.io/index.php?route=account/register');
 await expect(page).toHaveTitle("Register Account");
});

You can execute all of them together using the command below:

npx playwright test
test execution for splitting tests

Run the below command if you wish to target a specific group when needed:

npx playwright test --project="Admin Panel"
test execution for specific group

This approach becomes even more valuable in CI/CD pipelines. You could, for example, set up separate jobs for smoke, regression, and admin flows, enabling parallel execution and faster feedback. It’s also easier to isolate failures and rerun only the failed or flaky tests.

How to Use Playwright Project Dependencies?

In Playwright, you can define project dependencies in the playwright.config.ts file so one project runs after another. This enables shared sessions, sequential setup, cleanup tasks, and running only relevant tests per project.

Let’s dive into three practical ways to use project dependencies effectively.

Running Sequence of Projects

You can instruct Playwright to run one project only after another completes. This is useful when one project’s outcome is required for the next.

Let’s consider the following setup:

import { defineConfig } from '@playwright/test';


export default defineConfig({
 projects: [
   {
     name: 'setup-auth',
     testMatch: /.*setup.spec.js/,
   },
   {
     name: 'authenticated-tests',
     testMatch: /.*authenticated.spec.js/,
     use: {
       storageState: 'tmp/auth.json',
     },
     dependencies: ['setup-auth'],
   },
 ], 
});

In this case:

  • setup-auth runs first and stores a session in tmp/auth.json.
  • authenticated-tests uses that session to run further tests.

In the setup.spec.ts file, you might have:

test('login and save storage', async ({ page }) => {
   await page.goto('https://ecommerce-playground.lambdatest.io/index.php?route=account/login');
   await page.fill('#input-email', 'mytestuser@gmail.com');
   await page.fill('#input-password', 'test123');
   await page.click('//input[@type="submit"]');
   await page.context().storageState({ path: 'tmp/auth.json' });
 });

This ensures you only log in once, rather than in every test, saving time and avoiding unnecessary load on your system.

In the authenticated.spec.ts file, you might have:

test('access page already authenticated', async ({ page }) => {
   await page.goto('https://ecommerce-playground.lambdatest.io/index.php?route=account/account');
   await expect(page).toHaveTitle("My Account")
 });

You can run this project just by using the command below:

npx playwright test
test execution for running sequence of projects

Using Teardown and Cleanup After Tests

Sometimes, you need to reset the state, clear test data, or trigger a teardown routine once all relevant tests are complete. You can handle this by adding a dedicated "cleanup" project that runs after others.

Here’s an example of how to set it up:

export default defineConfig({
 projects: [
   {
     name: 'main-tests',
     testMatch: /.*.spec.js/,
   },
   {
     name: 'cleanup-db',
     testMatch: /.*cleanup.spec.js/,
     dependencies: ['main-tests'],
   },
 ], 
});

In the cleanup.spec.js file, you could have:


test('reset database', async () => {
   await fetch('http://localhost:3000/api/reset', { method: 'POST' });
});

Because it depends on main-tests, the cleanup will run after all test files in that project have been executed. This model prevents you from having to write teardown logic in afterAll() hooks spread across multiple test files.

Filtering Tests for Specific Projects

Sometimes a test should only run in a specific context. While you can always use test.skip() method or environment checks, a cleaner solution is to use the testMatch setting directly in the project definition.

For example:

export default defineConfig({
 projects: [
   {
     name: 'api-smoke',
     testMatch: /.*api-smoke.spec.js/,
   },
   {
     name: 'ui-regression',
     testMatch: /.*ui-regression.spec.js/,
   },
 ], 
});

Relying on testMatch inside projects ensures you keep logic out of test files and make your project configuration do the filtering. This makes your test suite easier to maintain, especially as the number of tests and scenarios grows.

Conclusion

Although often overlooked, Playwright projects offer a high level of control and structure that can elevate any test automation strategy. They make it possible to manage different testing contexts, from browser coverage to environment-specific configurations, in a clear and maintainable way.

When you define your projects thoughtfully, you benefit from:

  • Test files that stay clean and free from repeated setup logic.
  • Smarter execution flows, including parallel runs and ordered sequences.
  • Configurations tailored to different scenarios, such as login states, screen sizes, or deployment stages.

One of the most compelling aspects of this feature is its adaptability. You don’t need to start with a complex setup; even a simple multi-browser configuration adds value. As your test suite expands, the same foundation can support more advanced workflows without requiring major changes.

For teams using CI/CD, Playwright projects help break test execution into logical, manageable pieces, whether it’s prioritizing smoke checks, isolating environment-specific flows, or automating test cleanup.

Citations

Frequently Asked Questions (FAQs)

How do multiple projects work within a Playwright setup?
Playwright allows defining multiple projects in a single configuration file. Each project can target a different browser, viewport, or device. This setup enables efficient cross-environment testing without duplicating scripts. It simplifies test management and ensures consistent validation across various testing conditions.
Can projects in Playwright run in parallel?
Yes, Playwright supports parallel test execution across multiple projects. Each project runs independently, optimizing total run time. Parallelization improves CI performance, especially when testing across different browsers or devices. Proper resource allocation and isolation help prevent race conditions and unstable test behavior.
How can environment-specific testing be handled in Playwright projects?
You can define separate Playwright projects for staging, production, or development environments. Each project holds its own base URL, credentials, and test options. This structure avoids configuration conflicts, keeps environment data isolated, and ensures consistent execution across deployment stages without manual intervention.
How does Playwright manage device emulation within projects?
Projects can be configured with predefined device settings such as viewport, user agent, and input type. Using built-in device descriptors, Playwright can emulate popular mobile and tablet models. This approach centralizes mobile testing configurations, ensuring consistent behavior across multiple simulated environments.
Can Playwright projects use different test configurations?
Yes, each Playwright project can include unique settings such as retries, timeouts, storage states, and screenshot preferences. This flexibility allows teams to tailor test behavior per environment or device type. Well-organized configuration management ensures reliability and reduces the need for repetitive test setup code.
How does Playwright simplify multi-browser testing through projects?
Playwright projects allow defining configurations for Chromium, Firefox, and WebKit in a single suite. Each project runs with its assigned browser, eliminating redundant code. This makes it easy to validate app behavior across major browsers while maintaining one unified test structure.
How can Playwright projects be integrated into CI/CD pipelines?
Playwright projects integrate seamlessly with CI/CD tools like Jenkins, GitHub Actions, or GitLab CI. Each project can execute independently, enabling parallel runs for faster builds. By grouping configurations, teams gain better visibility over cross-browser test results and simplify pipeline maintenance.
What is the best way to organize test files in a Playwright project?
A clean Playwright project uses a modular folder structure with separate directories for tests, fixtures, and configurations. Keeping page objects and utilities in dedicated folders improves maintainability. Consistent naming and reusable patterns help teams scale test suites efficiently across multiple projects.
How can you manage test data across multiple Playwright projects?
Centralizing test data management ensures consistency. You can maintain shared fixtures or environment files accessed by all projects. Each project can override variables when needed. This structured approach reduces duplication, supports data-driven testing, and keeps environment-specific values isolated and easy to update.

Did you find this page helpful?

Helpful

NotHelpful

More Related Hubs

ShadowLT Logo

Start your journey with LambdaTest

Get 100 minutes of automation test minutes FREE!!