Managing multiple test environments is one of the most critical aspects of modern test automation. Whether you’re working with dev, staging, or production environments, your Playwright tests need to adapt seamlessly.
This comprehensive 2026 guide walks you through best-practice strategies for cross-environment testing in Playwright, helping you build scalable, maintainable, and future-proof automation frameworks.
Table of Contents
- What is Cross-Environment Testing?
- Why Cross-Environment Testing Is Challenging
- Advantages of Cross-Environment Testing
- How to Configure Multiple Environments in Playwright
- Method 1: Config File and Dotenv Package
- Method 2: Cross-env and Dotenv Package
- Best Practices for 2026
- CI/CD Integration
- Troubleshooting Common Issues
- Conclusion
What is Cross-Environment Testing?
Most modern applications operate across multiple environments, such as:
- Development (Dev) – rapid iteration and feature testing
- Staging / QA – pre-production validation
- Production (Prod) – real-world user conditions
Cross-environment testing ensures that your application behaves consistently and reliably across all these environments.
Each environment often differs in:
- Application URLs
- API endpoints
- Authentication credentials
- Feature flags
- Test data sets
Without a robust strategy, maintaining separate tests for each environment becomes tedious, error-prone, and expensive—especially in fast-paced Agile and CI/CD pipelines.
Why Cross-Environment Testing Is Challenging
In real-world projects, teams often struggle with:
- Hardcoded URLs and credentials
- Environment-specific test failures
- Duplicate test suites for each environment
- Increased maintenance overhead
- Slower release cycles
A well-designed Playwright framework eliminates these problems by allowing the same test scripts to run across all environments with zero code changes.
Advantages of Cross-Environment Testing
1. Confidence Across All Environments
Validate that your application works correctly in every deployment stage, not just locally.
2. Faster Releases with Fewer Surprises
Catch environment-specific bugs before they reach production, reducing hotfixes and rollback risks by up to 80%.
3. Consistent Application Behaviour
Ensure features, integrations, and workflows behave identically across environments.
4. Improved Configuration Validation
Verify that:
- Services are wired correctly
- Dependencies are properly configured
- Environment variables are set as expected
5. Reduced Maintenance & Execution Time
Run the same Playwright tests against multiple environments using configuration-driven execution—saving time and reducing technical debt.
How to Configure and Execute Playwright Tests in Multiple Environments
Prerequisites
Before diving in, ensure you have:
- Node.js 18+ (Node.js 20 LTS recommended for 2026)
- Playwright 1.40+ installed
- Basic understanding of TypeScript/JavaScript
- A Playwright project initialized (
npm init playwright@latest)
There are multiple ways to configure multiple environments in Playwright and perform cross-environment testing. I will discuss 2 proven approaches in this article.
1. Configure Multiple Environments in Playwright using the Config File and Dot env Package
This method uses a centralized JSON configuration file combined with environment variables for flexible environment management.
Install dot-env package
We require a package to load environment variables from the .env file. Open your Playwright project, go to the terminal and execute the below command:
npm install dotenv --save
Once the installation is successful, a dependency will be added to the package.json file.
Create config.json file
Go to the project’s root, create a new file as config.json and add configurations for different environments:
{
"Staging": {
"baseUrl": "https://staging.yourapp.com",
"userName": "[email protected]",
"password": "StagingPass123!"
},
"Production": {
"baseUrl": "https://yourapp.com",
"userName": "[email protected]",
"password": "ProdPass123!"
},
"Development": {
"baseUrl": "https://dev.yourapp.com",
"userName": "[email protected]",
"password": "DevPass123!"
}
}
The keys represent different environments, and for each environment, there are properties that define various configuration settings like base URL, Username, and Password.
Add Environment File
Create a new .env file in the project root folder. Add the environment key:
environment=StagingLoad the dot-env package
To utilize the dot-env package, we need to load it after successful installation. Go to the project root level and create a new file named config.ts. Import the required packages:
import config from './config.json';
import dotenv from 'dotenv';
dotenv.config();
The dotenv.config() function is called to load environment variables from the .env file. This allows the configuration to be adjusted based on the current environment.
Write logic to retrieve the configuration settings from the config.json file based on the current environment:
import config from './config.json';
import dotenv from 'dotenv';
dotenv.config();
export function getBaseUrl(): string {
const env = process.env.environment || 'Development';
return config[env].baseUrl;
}
export function getUserName(): string {
const env = process.env.environment || 'Development';
return config[env].userName;
}
export function getPassword(): string {
const env = process.env.environment || 'Development';
return config[env].password;
}
Three functions (getBaseUrl, getUserName, and getPassword) are exported, each responsible for retrieving specific information from the configuration based on the current environment.
The process.env.environment statement is used to retrieve the current environment from environment variables.
Read .env file variables in test scripts
Multiple environment setup is complete. Now let’s utilize it in our test scripts. Open your test file and use the following code:
import { test, expect, Page } from '@playwright/test';
import { loginPage } from '../page-objects/loginPage';
import { getBaseUrl, getUserName, getPassword } from '../config';
let page: Page;
test('Client App login', async ({ page }) => {
const loginpage = new loginPage(page);
await page.goto(getBaseUrl());
await loginpage.validUserLogin(getUserName(), getPassword());
await expect(loginpage.DashboardHeading).toBeVisible();
});
Execute the script using npx playwright test. The staging environment Base URL is launched and login is successful.
You can execute the same script on any other environment like production by simply changing environment=Production in the .env file. All configuration related to the Production environment will be automatically picked up from the config.json file.
2. Configuring multiple environments in Playwright with cross-env and dot-env package
This is the most popular approach where we use two npm packages to configure multiple environments in the Playwright test automation framework. This method is recommended for 2026 due to its flexibility and cross-platform compatibility.
Install Cross-Env Package
Cross-env is an npm package used to set and use environment variables across different operating systems (Windows, Mac, Linux). Install this package using the command:
npm install --save-dev cross-envFirst, install the dotenv package as discussed in Method 1 if you haven’t already.
Add Multiple Environment Files
Go to the root of the project and create separate .env files for each environment. Add baseURL and credential information in these environment files:
.env.dev
BASE_URL=https://dev.yourapp.com
[email protected]
PASSWORD=DevPass123!
API_URL=https://api-dev.yourapp.com
TIMEOUT=30000.env.staging
BASE_URL=https://staging.yourapp.com
[email protected]
PASSWORD=StagingPass123!
API_URL=https://api-staging.yourapp.com
TIMEOUT=30000.env.prod
BASE_URL=https://yourapp.com
[email protected]
PASSWORD=ProdPass123!
API_URL=https://api.yourapp.com
TIMEOUT=30000
Manage Environment Keys
To manage the environment keys seamlessly across different environments, we need to create an encapsulated class. Go to the utility folder, create a new class and add the following code:
export default class ENV {
public static BASE_URL = process.env.BASE_URL || 'http://localhost:3000';
public static USERNAME = process.env.USERNAME || '';
public static PASSWORD = process.env.PASSWORD || '';
public static API_URL = process.env.API_URL || 'http://localhost:8080';
public static TIMEOUT = parseInt(process.env.TIMEOUT || '30000', 10);
}We are exporting the class ENV as the default export of the module, making it available for use in other parts of the code. The purpose of this class is to centralize access to environment variables with proper fallback values.
Create a Global Setup file
Create a new file named GlobalSetup.ts in the utility folder and add the following code:
import { FullConfig } from "@playwright/test";
import dotenv from "dotenv";
async function globalSetup(config: FullConfig) {
try {
if (process.env.test_env) {
dotenv.config({
path: `.env.${process.env.test_env}`,
override: true
});
console.log('Loaded environment: ${process.env.test_env}');
console.log('Base URL: ${process.env.BASE_URL}');
} else {
console.log('No test_env specified, using default configuration');
}
} catch (error) {
console.error("Error loading environment variables:", error);
throw error;
}
}
export default globalSetup;
This code uses dotenv to load environment variables and checks if the test_env environment variable is set (process.env.test_env). If set, it locates the required environment file in the project folder and loads the environment variables from the corresponding .env file.
Configure the Playwright config file
To properly identify the environment and load the necessary information before executing scripts, include the global setup file in your Playwright configuration:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
outputDir: 'test-results',
globalSetup: "./utility/GlobalSetup.ts",
// Timeouts
timeout: 60000,
expect: {
timeout: 10000
},
// Reporter configuration
reporter: [
['html', { outputFolder: 'playwright-report' }],
['json', { outputFile: 'test-results/results.json' }]
],
// Test configuration
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
]
});
Create Scripts
Open the package.json file and navigate to the scripts section. Scripts are used to define and run various commands related to the project. Add the following scripts:
"scripts": {
"test": "playwright test",
"test:dev": "cross-env test_env=dev npx playwright test",
"test:staging": "cross-env test_env=staging npx playwright test",
"test:prod": "cross-env test_env=prod npx playwright test",
"test:dev:ui": "cross-env test_env=dev npx playwright test --ui",
"test:dev:headed": "cross-env test_env=dev npx playwright test --headed",
"test:dev:debug": "cross-env test_env=dev npx playwright test --debug",
"report": "playwright show-report"
}Modify Test scripts
Open the loginTest.spec.ts file and modify the code to utilize the cross-environment configuration. Import the ENV class and access the variables:
import { test, expect, Page } from '@playwright/test';
import { loginPage } from '../page-objects/loginPage';
import ENV from '../utility/env';
let page: Page;
test.describe('Client App Login Tests', () => {
test.beforeEach(async ({ page }) => {
console.log(`🧪 Testing on: ${process.env.test_env || 'default'} environment`);
});
test('Client App login', async ({ page }) => {
const loginpage = new loginPage(page);
await page.goto(`${ENV.BASE_URL}`);
await loginpage.validUserLogin(`${ENV.USERNAME}`, `${ENV.PASSWORD}`);
await expect(loginpage.DashboardHeading).toBeVisible();
});
});
Execution
Now all the setup is complete. To execute test cases, go to the terminal and type:
npm run test:prodThis command will:
- Look for the
test:prodscript in the scripts section - Load environment variables from the
.env.prodfile - Execute tests on the production environment
Other execution examples:
# Run on development environment
npm run test:dev
# Run on staging environment
npm run test:staging
# Run specific test file on staging
npm run test:staging -- loginTest.spec.ts
# Run with UI mode for debugging
npm run test:dev:ui
Best Practices for 2026
1. Security First – Never Commit Credentials
# Add to .gitignore
.env*
!.env.example
config.jsonCreate an .env.example file as a template:
BASE_URL=https://example.com
USERNAME=your_username
PASSWORD=your_password2. Validate Environment Configuration
Add validation to your GlobalSetup.ts:
function validateEnvironment(): void {
const required = ['BASE_URL', 'USERNAME', 'PASSWORD'];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
}
console.log('All required environment variables are set');
}
3. Use TypeScript for Type Safety
interface EnvironmentConfig {
readonly baseUrl: string;
readonly apiUrl: string;
readonly username: string;
readonly password: string;
readonly timeout: number;
}4. Add Environment Logging
test.beforeAll(async () => {
console.log('Environment Configuration:', {
env: process.env.test_env || 'default',
baseUrl: ENV.BASE_URL,
timeout: ENV.TIMEOUT
});
});5. Environment-Specific Test Execution
test('production-only smoke test', async ({ page }) => {
test.skip(process.env.test_env !== 'prod',
'This test only runs in production');
});
CI/CD Integration
GitHub Actions Example
Create .github/workflows/playwright.yml:
name: Playwright Tests - Multi Environment
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
strategy:
matrix:
environment: [dev, staging, prod]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npm run test:${{ matrix.environment }}
env:
TEST_ENV: ${{ matrix.environment }}
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ matrix.environment }}
path: playwright-report/
retention-days: 30
Jenkins Pipeline Example
pipeline {
agent any
parameters {
choice(name: 'ENVIRONMENT', choices: ['dev', 'staging', 'prod'], description: 'Select environment')
}
stages {
stage('Install Dependencies') {
steps {
sh 'npm ci'
sh 'npx playwright install --with-deps'
}
}
stage('Run Tests') {
steps {
sh "npm run test:${params.ENVIRONMENT}"
}
}
stage('Publish Report') {
steps {
publishHTML([
reportDir: 'playwright-report',
reportFiles: 'index.html',
reportName: "Playwright Report - ${params.ENVIRONMENT}"
])
}
}
}
}
Troubleshooting Common Issues
Issue 1: Environment Variables Not Loading
Problem: Tests fail because environment variables are undefined.
Solution: Verify the following:
- Check that
cross-envis installed:npm list cross-env - Ensure
.envfiles are in the project root - Verify
globalSetupis properly configured inplaywright.config.ts - Add logging to confirm environment loading:
console.log('Current env:', process.env.test_env);
console.log('BASE_URL:', process.env.BASE_URL);Issue 2: Tests Pass Locally but Fail in CI/CD
Problem: Different behavior between local and CI environments.
Solution:
- Ensure environment files are properly configured in CI/CD secrets
- Add environment validation in global setup
- Use explicit timeouts for slower CI environments
- Check for hardcoded values in tests
Issue 3: Switching Environments Requires Manual Changes
Problem: Need to manually update .env file to switch environments.
Solution: Use Method 2 (cross-env) with npm scripts:
# Just run the appropriate script
npm run test:dev
npm run test:staging
npm run test:prodIssue 4: Credentials Accidentally Committed to Git
Problem: Sensitive data exposed in version control.
Solution:
- Immediately rotate all compromised credentials
- Remove files from Git history:
git filter-branchorBFG Repo-Cleaner - Update
.gitignoreto prevent future commits - Use secret management tools for production
Conclusion
Configuring multiple environments in a test automation framework is a best practice that helps identify and address potential issues across different environments, improving overall reliability and product quality.
This guide provides a detailed explanation of how to configure multiple environments in the Playwright automation framework and execute scripts without modifying test code.
Key Takeaways:
✅ Always use environment variables for sensitive data – Never hardcode credentials
✅ Implement proper TypeScript typing – Catch configuration errors at compile time
✅ Validate your environment setup – Fail fast with clear error messages
✅ Integrate with CI/CD – Automate cross-environment testing in your pipeline
✅ Monitor and log environment-specific behaviours – Debug issues faster
✅ Use cross-env for cross-platform compatibility – Works on Windows, Mac, and Linux
✅ Create separate environment files – Keep configurations organized and maintainable
Next Steps and Resources
Ready to level up your Playwright skills? Check out these related guides:
- 📚 How To Build Playwright Page Object Model Framework
- 💻 Complete GitHub Repository with Code Examples
- 🎯 The Ultimate List of Playwright Interview Questions
- 🚀 How To Install Playwright Framework
- ⚖️ Playwright vs Cypress vs Selenium: Which Is Right for You?
Frequently Asked Questions (FAQ)
Q: Which method should I use for configuring multiple environments in Playwright?
A: Method 2 (cross-env + dotenv) is recommended for 2026 as it offers better cross-platform support and cleaner separation of environment configurations.
Q: How do I secure sensitive credentials in my Playwright tests?
A: Never commit .env files to Git. Use environment variables in CI/CD, secret management tools like Azure Key Vault or AWS Secrets Manager, and add .env* to your .gitignore file.
Q: Can I run Playwright tests on multiple environments in parallel?
A: Yes! Configure your CI/CD pipeline to run tests in parallel across different environments using matrix strategies (shown in the GitHub Actions example above).
Q: What’s the difference between dotenv and cross-env?
A: dotenv loads environment variables from .env files, while cross-env sets environment variables in a cross-platform way. They work together for comprehensive environment management.
Q: How do I debug environment-specific test failures?
A: Use environment logging, run tests in headed mode (--headed), enable debug mode (--debug), and compare environment configurations between working and failing environments.
About the Author: Varsha Rajput is a test automation expert specializing in Playwright, Selenium, and modern testing frameworks. Connect on LinkedIn | GitHub
Was this guide helpful? Share it with your team and subscribe to AutomationQaHub for more testing insights.
Visit here to learn how to implement the Playwright POM framework. Refer GitHub repo for the code.