Monitor a service across staging and production
This guide walks through the full environments workflow: creating environments in the catalog, attaching a system to them, and writing one HTTP health check that runs against each environment’s base URL using {{ environment.baseUrl }} templating. You end with per-environment health values, per-environment run history, and the system rollup — all from a single check configuration.
Read Environments first for the mental model.
What you need
Section titled “What you need”- A Checkstack instance with the HTTP plugin installed.
- The
catalog.environments.manageandhealthcheck.configuration.manageaccess rules (both are in the built-in administrator role).
1. Create the environments
Section titled “1. Create the environments”Open Catalog management from the sidebar, then select the Environments tab.
Create a staging environment
Section titled “Create a staging environment”- Click Add environment.
- Set Name to
staging. - Under Custom fields, add:
- Key:
baseUrl, Value:https://staging.example.com
- Key:
- Click Save.
Create a production environment
Section titled “Create a production environment”- Click Add environment again.
- Set Name to
production. - Under Custom fields, add:
- Key:
baseUrl, Value:https://api.example.com
- Key:
- Click Save.
2. Attach the system to both environments
Section titled “2. Attach the system to both environments”- Navigate to the system you want to monitor (for example
Payments API) in the catalog. - In the system editor, open the Environments section.
- Select both
stagingandproduction. - Save the system.
The system now belongs to both environments. On the next health check run the executor reads this membership from the catalog and fans out accordingly.
3. Create the HTTP health check with a templated URL
Section titled “3. Create the HTTP health check with a templated URL”- Navigate to Health Checks and click Create Check.
- Select the HTTP Health Check strategy.
- In the editor:
- Name:
Payments API /healthz - Interval:
60
- Name:
Add the Request collector
Section titled “Add the Request collector”-
Select Add Collector and choose Request.
-
In the collector’s URL field, enter:
{{ environment.baseUrl }}/healthz -
Set Method to
GETand Expected status to200. -
Leave the other fields at their defaults.
The URL field is marked x-templatable. At run time, before the HTTP request is made, the executor renders {{ environment.baseUrl }} against the resolved environment’s custom fields. The result for staging is https://staging.example.com/healthz; for production it is https://api.example.com/healthz.
Assign to the system
Section titled “Assign to the system”- In the Systems section of the editor, select the
Payments APIsystem. - Save the health check.
4. Configure the environment fan-out
Section titled “4. Configure the environment fan-out”Navigate to the system’s health check assignments (Health Checks > select the system > Assignments), select the Payments API /healthz assignment, and open the Execution panel.
The Environments section offers three modes:
| Mode | Meaning |
|---|---|
| All environments | Run once per environment the system belongs to. Adding or removing the system from an environment updates the fan-out on the next tick. |
| Specific | Run only for the environments you select explicitly. |
| None | Opt out of fan-out; run exactly once with no environment context. |
Leave All environments selected (the default). With staging and production attached, the check now fans out to two runs per tick.
5. Watch the per-environment results
Section titled “5. Watch the per-environment results”After the first run, open the system’s health check drawer:
- The runs table shows one row per environment per tick. The Environment column identifies which environment each row belongs to.
- Run history groups by environment so you can compare staging and production latency and failure rates independently.
6. Read per-environment health in automations
Section titled “6. Read per-environment health in automations”The health triggers (healthcheck.system_degraded, healthcheck.system_health_restored, healthcheck.system_health_changed) fire for both per-environment changes and the system rollup:
- A per-environment change carries
trigger.payload.environmentId(the environment id) andtrigger.payload.systemId. - The system rollup change carries only
trigger.payload.systemId(noenvironmentId).
Open an incident only when production is unhealthy
Section titled “Open an incident only when production is unhealthy”trigger: healthcheck.system_degradedfilter: "trigger.payload.environmentId == 'production'"actions: - openIncident: title: "Production degraded: {{ trigger.payload.systemId }}"Alert on any environment change (default behavior)
Section titled “Alert on any environment change (default behavior)”An automation that does not reference environmentId continues to fire off the system rollup, exactly as it did before environments. The rollup is the worst status across all environments, so existing automations keep working without modification.
7. Use environment values in scripts
Section titled “7. Use environment values in scripts”If you are using a script collector instead of (or alongside) the HTTP collector, the resolved environment is available in two ways:
Shell script:
echo "checking ${CHECKSTACK_ENV_NAME} at ${CHECKSTACK_ENV_BASE_URL}"curl -sf "${CHECKSTACK_ENV_BASE_URL}/healthz" || exit 1The custom field baseUrl is injected as CHECKSTACK_ENV_BASE_URL (camelCase split to UPPER_SNAKE_CASE). See Script health checks for the full variable reference.
Inline TypeScript:
import { defineHealthCheck } from "@checkstack/healthcheck";
const baseUrl = context.environment?.fields.baseUrl ?? "http://localhost";const resp = await fetch(`${baseUrl}/healthz`);export default defineHealthCheck({ success: resp.ok, message: `${context.environment?.name ?? "env-less"}: HTTP ${resp.status}`,});context.environment is undefined when the run has no environment (the None assignment mode, or All environments with no membership).
What you built
Section titled “What you built”| Component | What it does |
|---|---|
staging environment | Carries baseUrl: https://staging.example.com |
production environment | Carries baseUrl: https://api.example.com |
Payments API system | Belongs to both environments |
Payments API /healthz check | One config, runs against each environment’s baseUrl per tick |
| Per-environment health | payments-api::staging and payments-api::production tracked independently |
| System rollup | Worst-status rollup, same id as before, picked up by existing automations |
To extend this pattern to more environments, add a new environment in the catalog, attach the system to it, and the next tick fans out automatically - no check config change needed.