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_USERandE2E_PASSas secrets; never commit real credentials. - Do not upload
.auth/user.jsonas an artifact; it holds a live session token.
Related guides
How to Pass Secrets and Environment Variables to E2E Tests in GitHub ActionsSupply API keys, test logins, and base URLs to E2E tests in GitHub Actions through repo secrets and env, keep…
How to Seed Test Data Before E2E Tests in GitHub ActionsSeed a deterministic dataset before browser tests run in GitHub Actions by running migrations and a seed scri…