PRACTICAL GUIDE / playwright project dependencies

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.

By The Testing AcademyUpdated July 11, 20269 min read
All field guides
In this guide10 sections
  1. Model Setup as a Dependency Graph
  2. Configure Setup, Dependents, and Teardown
  3. Produce a Saved Prerequisite Deliberately
  4. Make Teardown Idempotent and Scoped
  5. Preserve Observability in Setup Failures
  6. Understand Filtering and no-deps
  7. Separate Run-Level and Test-Level State
  8. Analyze Lifecycle Failures and Tradeoffs
  9. Operational Checklist for Project Dependencies
  10. Action Plan

What you will learn

  • Model Setup as a Dependency Graph
  • Configure Setup, Dependents, and Teardown
  • Produce a Saved Prerequisite Deliberately
  • Make Teardown Idempotent and Scoped

Suite-wide setup is production code for the test system. It authenticates users, creates tenants, seeds baselines, and decides whether hundreds of tests are allowed to start. Hiding that work in a callback outside the normal runner makes its failures unusually hard to trace at the moment they have the largest blast radius.

Playwright project dependencies turn prerequisites into named test projects. Setup appears in the report, can use fixtures, can record a trace, and participates in retries and project selection. A linked teardown project owns cleanup after dependent projects complete. The result is a visible dependency graph rather than an implicit before-everything script.

Model Setup as a Dependency Graph

Define each prerequisite by what it produces and which projects consume it. An authentication setup may produce a storage-state file. A tenant setup may create a run-scoped tenant ID. Browser projects depend on those outputs. Teardown removes only resources created by that run.

The official Playwright setup and teardown guide recommends project dependencies because they integrate with reports, traces, fixtures, browser management, parallelism, and normal configuration. This does not mean every shell command belongs in a test. It means critical test prerequisites benefit from runner ownership and artifacts.

Animated field map

Observable Project Setup and Teardown

A setup project creates a saved prerequisite, dependent projects consume it, and teardown cleans the run after artifacts are retained.

  1. 01 / setup project

    Setup project

    Run prerequisite work as named tests with fixtures and retries.

  2. 02 / saved prerequisite

    Saved prerequisite

    Publish scoped auth or data state for explicit consumers.

  3. 03 / dependent projects

    Dependent projects

    Execute browser or environment coverage after setup passes.

  4. 04 / test artifacts

    Test artifacts

    Preserve reports, traces, and identifiers for diagnosis.

  5. 05 / teardown project

    Teardown project

    Delete only run-owned resources after dependents finish.

Keep the graph shallow. If setup A depends on B, which depends on C, failures become harder to localize and filtered runs become expensive. Combine steps that create one atomic prerequisite, but separate lifecycles that have different consumers or cleanup.

Configure Setup, Dependents, and Teardown

Give setup and teardown narrow testMatch patterns so product specs cannot accidentally join those projects. The setup project's teardown property names the cleanup project; consumer projects list setup in dependencies.

TypeScript
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test'

export default defineConfig({
  testDir: './tests',
  reporter: [['html'], ['line']],
  use: {
    baseURL: process.env.APP_URL,
    trace: 'retain-on-failure',
  },
  projects: [
    {
      name: 'run setup',
      testMatch: /run\.setup\.ts/,
      teardown: 'run teardown',
    },
    {
      name: 'run teardown',
      testMatch: /run\.teardown\.ts/,
    },
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
      dependencies: ['run setup'],
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
      dependencies: ['run setup'],
    },
  ],
})

This graph runs setup before either browser project and schedules teardown after dependent work. The setup is not a beforeAll inside every project, so its ownership and report entry remain distinct.

Use names that describe the prerequisite, such as authenticated buyer setup, when a suite has several setup branches. Generic names like setup become confusing in command output and HTML reports.

Produce a Saved Prerequisite Deliberately

An authentication setup can sign in through the UI and save browser state for dependent projects. Keep the output path stable for the current runner invocation, ignored by source control, and isolated from other concurrent jobs.

TypeScript
// tests/run.setup.ts
import { expect, test as setup } from '@playwright/test'
import path from 'node:path'

const runId = process.env.QA_RUN_ID
if (!runId) throw new Error('QA_RUN_ID is required')

const authFile = path.join('playwright', '.auth', `${runId}-buyer.json`)

setup('authenticate run-scoped buyer', async ({ page }, testInfo) => {
  await page.goto('/sign-in')
  await page.getByLabel('Email').fill(process.env.QA_BUYER_EMAIL ?? '')
  await page.getByLabel('Password').fill(process.env.QA_BUYER_PASSWORD ?? '')
  await page.getByRole('button', { name: 'Sign in' }).click()
  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()

  await page.context().storageState({ path: authFile })
  await testInfo.attach('setup-identity', {
    body: Buffer.from(JSON.stringify({ runId, role: 'buyer' })),
    contentType: 'application/json',
  })
})

Dependent projects need the same computed path in use.storageState, often through a small configuration function. Do not attach credentials, cookies, or the storage-state file to a broadly accessible report. The useful diagnostic is the non-secret run and role identity.

If setup creates data through an API, assert the response and capture created resource IDs. Avoid broad seed scripts that return success before background work is ready. Setup should finish only when the prerequisite contract is observable by consumers.

Make Teardown Idempotent and Scoped

Teardown should remove resources by run ownership, tolerate already-absent records, and refuse to issue an unscoped delete. It must be safe after a partial setup and after a dependent test has already removed one resource.

TypeScript
// tests/run.teardown.ts
import { expect, test as teardown } from '@playwright/test'

teardown('remove run-scoped test resources', async ({ request }) => {
  const runId = process.env.QA_RUN_ID
  if (!runId) throw new Error('Refusing teardown without QA_RUN_ID')

  const response = await request.delete('/api/test-support/runs/current', {
    params: { runId },
  })

  expect([200, 204, 404]).toContain(response.status())
})

The endpoint should authenticate the caller and verify ownership; a query parameter alone is not a security boundary. Treat 404 as success only if the cleanup contract is idempotent. If setup writes local state, remove it through a controlled cleanup mechanism, but never delete a shared directory with an unvalidated environment-derived path.

No teardown mechanism can guarantee execution after every infrastructure failure. Add server-side TTLs or a scheduled sweeper for ephemeral tenants and leases. Project teardown handles normal lifecycle; expiration handles abandoned lifecycle.

Preserve Observability in Setup Failures

Setup failures should show the same evidence expected from product tests: a named step, focused attachments, trace, and relevant request status. Since dependent projects will not run when their prerequisite fails, the setup report needs to stand on its own.

Keep assertions close to each created prerequisite. If a script creates a tenant, enables a flag, and authenticates a user before one final expect(true), the report cannot identify which transition failed. Separate setup tests are useful when outputs are independent; use steps when they must succeed atomically as one prerequisite.

Retries can be appropriate for transient setup, but they must not duplicate resources. Use run-scoped idempotency keys and upsert semantics. A retry that creates a second tenant may pass setup while teardown removes only one, leaving both test pollution and an inaccurate report.

Understand Filtering and no-deps

Test filters select primary tests first. If those tests belong to projects with dependencies, Playwright also runs all tests in the dependency projects. This applies to project and location filtering, grep, test.only, and sharding selection. Design setup to be idempotent because each runner invocation that selects a dependent project owns its prerequisite lifecycle.

--no-deps skips dependencies and teardowns. It is useful when a developer intentionally reuses an already prepared local environment or wants to isolate one product test during diagnosis. It is dangerous in normal CI because the run can consume stale auth or data and omit cleanup. Make the exceptional workflow explicit in developer documentation or scripts rather than using --no-deps as a routine speed switch.

Selecting the setup project directly is a useful diagnostic. It lets an engineer reproduce prerequisite failures without waiting for browser projects, inspect its trace, and verify generated state before running consumers.

Separate Run-Level and Test-Level State

Project setup is a good home for immutable reference data, a dedicated tenant, authenticated roles, or service readiness. It is a poor home for one mutable cart, shared order, or user preference that parallel tests will change. Those resources belong in test- or worker-scoped fixtures with clear isolation.

This division also controls cost. Run-level setup amortizes expensive stable work. Test fixtures preserve independence for volatile records. When a supposedly immutable baseline needs restoration after each test, it is not actually run-level state.

For multiple environments, avoid creating a dependency for every Cartesian combination automatically. Decide whether setup output is browser-independent, environment-specific, or role-specific, and model only those dimensions. Duplicate setup projects can contend for the same account if their ownership is not explicit.

Analyze Lifecycle Failures and Tradeoffs

Project dependencies improve visibility but add graph execution and can increase filtered-run time. Use them where the shared prerequisite and observability justify that cost.

SymptomLikely causeRepair
Setup passes but consumers cannot use stateOutput path or environment identity differsCompute paths from one shared configuration source
Retry creates duplicate tenantsSetup is not idempotentAdd run-scoped idempotency and return existing output
Teardown deletes unrelated dataCleanup lacks ownership boundaryRequire and validate run-specific identifiers
Filtered test unexpectedly runs setupDependency execution is working as configuredUse direct setup diagnosis or intentional --no-deps only
Setup trace lacks useful evidenceCritical work occurs outside named assertions or stepsMove work into setup tests and attach focused metadata
Browser projects interfere after setupMutable data was shared at run scopeMove it to isolated fixtures or namespace each test

globalSetup can still suit process-level integration that cannot be represented as tests, but the team must build browser handling, tracing, and error artifacts manually. Choose it for a concrete constraint, not familiarity.

Operational Checklist for Project Dependencies

  • Name each setup project by the prerequisite it produces.
  • Keep testMatch narrow for setup and teardown files.
  • Declare consumers through dependencies and cleanup through teardown.
  • Make setup retry-safe with run-scoped idempotency keys.
  • Save only non-secret diagnostic metadata in reports.
  • Keep auth state ignored, isolated per run, and access controlled.
  • Make cleanup idempotent and reject unscoped deletion.
  • Add TTL or sweeper recovery for abandoned remote resources.
  • Reserve mutable records for test- or worker-scoped fixtures.
  • Treat --no-deps as an explicit diagnostic exception.

Action Plan

Choose one opaque global setup task and identify its output, consumers, and cleanup boundary. Convert it into a narrowly matched setup test with a run-scoped identifier, assertions at each critical transition, and trace retention. Configure one dependent browser project and an idempotent teardown project, then test four paths: normal success, setup failure, dependent failure, and interrupted cleanup. Expand the graph only after reports make each path easier to diagnose and no prerequisite is shared beyond the scope it can safely support.

// 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.

Code PROMODE / 10% offJoin the batch

The Testing Academy editorial desk

Practical QA guidance built around test evidence, production tradeoffs, and interview-ready explanations.

Published July 11, 2026 / Reviewed July 11, 2026

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.

  1. 01
    Playwright documentation

    Microsoft

    Canonical API, locator, fixture, browser, and test-runner behavior.

  2. 02
    Playwright best practices

    Microsoft

    Official guidance for resilient tests, isolation, and user-facing locators.

  3. 03
    WebDriver standard

    W3C

    The browser automation protocol specification used by major automation stacks.

FAQ / QUICK ANSWERS

Questions testers ask

What are Playwright project dependencies?

They are named projects that must run before another project's selected tests. They model setup as ordinary Playwright tests, so fixtures, retries, traces, and report entries are available.

Why use a setup project instead of globalSetup?

A setup project integrates with the Playwright runner and its artifacts, fixtures, configuration, and reporting. globalSetup remains useful for specialized process-level work, but it requires more manual observability and browser management.

How does a Playwright teardown project run?

Set the setup project's teardown property to the teardown project name. The teardown project runs after projects that depend on that setup have completed.

Do project dependencies run when tests are filtered?

When selected primary tests belong to a project with dependencies, Playwright also runs the dependency tests. The --no-deps option deliberately skips dependencies and teardowns, so use it only when prerequisites already exist.

Should a setup project create shared test data?

It can create immutable or safely partitioned prerequisites, but mutable records shared by parallel tests invite collisions. Prefer a run-level tenant or baseline plus per-test resource isolation.