Environment variables let you configure values, like API URLs, feature flags, or test credentials, differently across environments without changing test code. This lesson covers every way to set and read them in Cypress.
Cypress.env() and Where Values Come From
Cypress.env(key) reads a value from Cypress's environment variable store, which can be populated from several sources: the env block in cypress.config.js, a cypress.env.json file, CLI flags, or actual OS environment variables prefixed with CYPRESS_.
// cypress.config.js
export default defineConfig({
e2e: {
env: {
apiUrl: 'https://staging-api.example.com',
},
},
});
// in a spec file
cy.request(`${Cypress.env('apiUrl')}/health`);
Cypress.env('apiUrl') reads the value configured in the env block, kept separate from Cypress's own core settings like baseUrl.
Ways to Set Environment Variables
// cypress.config.js
env: { apiUrl: '...' }
// cypress.env.json (gitignored for secrets)
{ "apiUrl": "..." }
// CLI flag
npx cypress run --env apiUrl=https://staging-api.example.com
// OS environment variable
CYPRESS_apiUrl=https://staging-api.example.com npx cypress run
CLI --env flags override config file and cypress.env.json values.
OS variables prefixed with CYPRESS_ are automatically picked up by Cypress.
cypress.env.json is a good place for local secrets and should typically be gitignored.
Later sources in Cypress's resolution order override earlier ones for the same key.
Environment Variable Precedence Cheat Sheet
From lowest to highest priority when the same key is set in multiple places.
Source
Priority
cypress.config.jsenv block
Lowest
cypress.env.json file
Low-medium
CYPRESS_* OS environment variables
Medium-high
--env CLI flag
Highest
Reading Environment Variables in Tests
Cypress.env() called with no arguments returns the entire environment object, useful for debugging what values are actually active during a given run.
it('logs the current environment config', () => {
cy.log(JSON.stringify(Cypress.env()));
expect(Cypress.env('apiUrl')).to.be.a('string');
});
Handling Secrets Safely
Never commit real secrets (API keys, test account passwords) directly into cypress.config.js or a tracked cypress.env.json. Instead, inject them via CI-provided environment variables (CYPRESS_*) at runtime, keeping them out of source control entirely.
Add cypress.env.json to .gitignore if it will ever contain real secrets.
Configure secrets as CI environment variables prefixed with CYPRESS_.
Never log full secret values with cy.log() or console.log(), even during debugging.
Supporting Multiple Environments
Cypress's --env flag and Node-level config profiles (via configFile or environment-specific config functions) both support running the same suite against different environments, local, staging, production-like, without duplicating spec files.
npx cypress run --env environmentName=staging --config baseUrl=https://staging.example.com
Common Mistakes
Committing real secrets into a tracked cypress.env.json or directly into cypress.config.js.
Confusing Cypress.env() (custom values) with core Cypress config like Cypress.config('baseUrl').
Not understanding the precedence order, leading to confusion about why a CLI flag isn't taking effect.
Hardcoding environment-specific URLs directly in spec files instead of using environment variables.
Key Takeaways
Cypress.env(key) reads custom environment variables from several possible sources.
CLI --env flags have the highest precedence, overriding config files and cypress.env.json.
Secrets should be injected via CI environment variables, never committed to source control.
The same suite can target multiple environments by varying environment variables and config, not spec files.
Pro Tip
Log Cypress.env() once at the very start of a suspicious CI run when a test behaves differently than locally, mismatched or missing environment variables are one of the most common, and quickest to diagnose, causes of "works locally, fails in CI."
You now know how to manage environment variables. Next, look at broader Cypress Configuration options in cypress.config.js.