Skip to content
Latchkey

How to Reuse Login State in Playwright E2E on GitHub Actions

Authenticate once in a setup project, save the session to storageState, and load it in every test so no spec logs in through the UI.

A setup project performs the login and writes storageState to a file; other projects declare dependencies: ['setup'] and load that file, so tests start already authenticated.

Setup project

auth.setup.ts
import { test as setup } from '@playwright/test'

setup('authenticate', async ({ page }) => {
  await page.goto('/login')
  await page.getByLabel('Email').fill(process.env.E2E_USER)
  await page.getByLabel('Password').fill(process.env.E2E_PASS)
  await page.getByRole('button', { name: 'Sign in' }).click()
  await page.context().storageState({ path: '.auth/user.json' })
})

playwright.config.ts

playwright.config.ts
projects: [
  { name: 'setup', testMatch: /auth\.setup\.ts/ },
  {
    name: 'chromium',
    use: { ...devices['Desktop Chrome'], storageState: '.auth/user.json' },
    dependencies: ['setup'],
  },
]

Gotchas

  • Supply E2E_USER and E2E_PASS as secrets; never commit real credentials.
  • Do not upload .auth/user.json as an artifact; it holds a live session token.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →