> ## Documentation Index
> Fetch the complete documentation index at: https://checkly-422f444a-agent-clarify-maintenance-uptime-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitor multiple environments

> Choose how to test and continuously monitor development, staging, and production environments with Checkly.

Checkly does not create a separate Environment resource. Instead, you combine CLI projects, environment variables, and your CI/CD pipeline to target each application environment.

Use a separate Checkly CLI project for every long-lived environment that you want to monitor continuously. Use `checkly test` without deploying a project when you only need to validate an ephemeral environment, such as a pull request preview.

## Choose an approach

| What you want to do                                                          | Recommended approach                                                                                                             |
| ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Test an ephemeral preview deployment                                         | Run `checkly test` with temporary environment variables. Do not deploy it as a scheduled monitor.                                |
| Continuously monitor the same checks in development, staging, and production | Deploy the same check code as a separate CLI project for each environment. Give every project a unique, stable `logicalId`.      |
| Continuously monitor different checks in each environment                    | Use a separate project for each environment and select shared and environment-specific check files in the project configuration. |

<Note>
  A Checkly CLI project is a deployment boundary, not the same thing as a Git branch or application environment. Your pipeline decides which branch deploys which project.
</Note>

## Test an ephemeral environment

Pass runtime values to `checkly test` with `--env` (`-e`) or `--env-file`. The values apply only to that test session and do not update your scheduled monitors.

```bash Terminal theme={null}
npx checkly test \
  --env ENVIRONMENT_URL="https://preview-123.example.com" \
  --env API_TOKEN="$PREVIEW_API_TOKEN"
```

This approach works well for pull request previews and other short-lived deployments. See [CI/CD](/integrations/ci-cd/overview) for the recommended test-before-deploy workflow.

## Continuously monitor multiple environments

The following example deploys one shared API check to development, staging, and production. Each deployment has:

* A unique project identity and separate deployment history
* The same project-scoped check and group logical IDs
* Its own URL and secret API token
* Its own schedule, locations, and tags

<Accordion title="Prerequisites">
  - A Checkly account and a Checkly CLI project
  - `CHECKLY_API_KEY` and `CHECKLY_ACCOUNT_ID` configured in your CI provider
  - A persistent deployment URL and credentials for each environment
  - A CI branch or deployment event that identifies the target environment
</Accordion>

<Steps>
  <Step title="Define a stable project identity for each environment">
    Read the target environment from your CI pipeline and map it to a unique project `logicalId`.

    ```typescript checkly.config.ts theme={null}
    import { defineConfig } from "checkly"
    import { Frequency } from "checkly/constructs"

    type Environment = "development" | "staging" | "production"

    const environments: Record<Environment, {
      projectName: string
      logicalId: string
      frequency: Frequency
      locations: string[]
    }> = {
      development: {
        projectName: "My app - Development",
        logicalId: "my-app-development",
        frequency: Frequency.EVERY_30M,
        locations: ["us-east-1"],
      },
      staging: {
        projectName: "My app - Staging",
        logicalId: "my-app-staging",
        frequency: Frequency.EVERY_10M,
        locations: ["us-east-1"],
      },
      production: {
        projectName: "My app - Production",
        logicalId: "my-app-production",
        frequency: Frequency.EVERY_5M,
        locations: ["us-east-1", "eu-west-1"],
      },
    }

    const environment = process.env.CHECKLY_ENVIRONMENT as Environment | undefined

    if (!environment || !environments[environment]) {
      throw new Error(
        "Set CHECKLY_ENVIRONMENT to development, staging, or production"
      )
    }

    const target = environments[environment]

    export default defineConfig({
      projectName: target.projectName,
      logicalId: target.logicalId,
      checks: {
        activated: true,
        checkMatch: "**/__checks__/**/*.check.ts",
        frequency: target.frequency,
        locations: target.locations,
        tags: [environment],
      },
    })
    ```

    Keep each project `logicalId` stable. Changing it creates a different project instead of updating the existing environment's monitors.
  </Step>

  <Step title="Store environment-specific runtime values with the checks">
    Define values on a check or group when scheduled runs need them. In this example, the CLI reads the values from CI while deploying and stores them on the environment's check group.

    ```typescript __checks__/api.check.ts theme={null}
    import {
      ApiCheck,
      AssertionBuilder,
      CheckGroupV2,
    } from "checkly/constructs"

    const environment = process.env.CHECKLY_ENVIRONMENT
    const environmentUrl = process.env.ENVIRONMENT_URL
    const apiToken = process.env.API_TOKEN

    if (!environment || !environmentUrl || !apiToken) {
      throw new Error(
        "Set CHECKLY_ENVIRONMENT, ENVIRONMENT_URL, and API_TOKEN"
      )
    }

    const environmentGroup = new CheckGroupV2("application", {
      name: `My app - ${environment}`,
      tags: [environment],
      environmentVariables: [
        { key: "ENVIRONMENT_URL", value: environmentUrl },
        { key: "API_TOKEN", value: apiToken, secret: true },
      ],
    })

    new ApiCheck("api-health", {
      name: `API health - ${environment}`,
      group: environmentGroup,
      request: {
        method: "GET",
        url: "{{{ENVIRONMENT_URL}}}/health",
        headers: [
          { key: "Authorization", value: "Bearer {{{API_TOKEN}}}" },
        ],
        assertions: [AssertionBuilder.statusCode().equals(200)],
      },
    })
    ```

    The `application` and `api-health` logical IDs can stay the same because resource logical IDs are scoped to their CLI project. Setting `secret: true` prevents Checkly from exposing the token after it is saved.
  </Step>

  <Step title="Deploy the project that matches the application environment">
    Map each persistent application environment to one Checkly project in your pipeline. Run the matching command after that environment's application deployment succeeds.

    | Application branch | `CHECKLY_ENVIRONMENT` | Checkly project `logicalId` |
    | ------------------ | --------------------- | --------------------------- |
    | `develop`          | `development`         | `my-app-development`        |
    | `staging`          | `staging`             | `my-app-staging`            |
    | `main`             | `production`          | `my-app-production`         |

    For example, the staging deployment job would run:

    ```bash Terminal theme={null}
    CHECKLY_ENVIRONMENT=staging \
    ENVIRONMENT_URL="https://staging-api.example.com" \
    API_TOKEN="$STAGING_API_TOKEN" \
    npx checkly deploy
    ```

    The production job uses the same source files but supplies production values:

    ```bash Terminal theme={null}
    CHECKLY_ENVIRONMENT=production \
    ENVIRONMENT_URL="https://api.example.com" \
    API_TOKEN="$PRODUCTION_API_TOKEN" \
    npx checkly deploy
    ```

    Review the deployment changes before confirming them. After you have verified the mapping, a non-interactive CI job can use `--force` to skip the confirmation prompt.
  </Step>
</Steps>

<Warning>
  A deploy reconciles only the project selected by its `logicalId`, but resources removed from that project are deleted by default. Run [`checkly deploy --preview`](/cli/checkly-deploy#command-options) when changing branch mappings or environment-specific check selection.
</Warning>

## Run different checks in each environment

When an environment needs additional or different checks, keep shared checks in one directory and select the environment-specific directory from your configuration:

```typescript checkly.config.ts theme={null}
const sharedChecks = "**/__checks__/shared/**/*.check.ts"
const environmentChecks = `**/__checks__/${environment}/**/*.check.ts`

export default defineConfig({
  projectName: target.projectName,
  logicalId: target.logicalId,
  checks: {
    checkMatch: [sharedChecks, environmentChecks],
    frequency: target.frequency,
    locations: target.locations,
    tags: [environment],
  },
})
```

For example, `__checks__/shared/` can contain health and login checks, while `__checks__/production/` contains production-only purchase checks. Each environment remains authoritative for its own deployed project.

## Understand environment variable behavior

| Variable source                      | Available when                            | Persists for scheduled monitoring                                                              |
| ------------------------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------- |
| Shell or CI environment              | The CLI parses your config and constructs | Only when the value is written into a deployed construct, such as a group environment variable |
| `checkly test --env` or `--env-file` | That test session runs in Checkly         | No                                                                                             |
| Check- or group-level variable       | A deployed check runs                     | Yes, for that check or group                                                                   |
| Global variable                      | Any check in the account runs             | Yes, account-wide                                                                              |

Prefer check- or group-level variables when the same key needs a different value in each environment. A global `ENVIRONMENT_URL`, for example, can hold only one account-wide value and is therefore not a good fit for separate development, staging, and production targets.

Use [secrets](/platform/secrets) for credentials, tokens, and other sensitive values. For more detail about build-time and runtime values, see [CLI environment variables](/cli/environment-variables) and [environment variables and secrets](/platform/variables).

## Playwright Check Suites

For Playwright Check Suites, keep URLs and credentials in runtime environment variables and read them from `process.env` in your Playwright configuration or fixtures. The project-per-environment model remains the same.

See [environment-aware Playwright tests](/guides/playwright-environments) for configuring `baseURL`, fixtures, and local-versus-Checkly execution.
