Monitors as Code

What is Monitors as Code?

Monitors as Code (MaC) lets you define Monte Carlo monitors in YAML files and manage them with the Monte Carlo CLI. Optionally deploy through your CI/CD pipeline for automated, version-controlled monitor management. The CLI reads your YAML and syncs the declared state to Monte Carlo — creating, updating, or deleting monitors as needed.

New to MaC? Start with the Setting Up guide — it walks you from CLI install to your first running monitor. This page is the reference for project configuration, monitor types, and deployment.

📘

Already using dbt? Apply monitors straight from your dbt project.

Two options, no separate tooling required:

  • Embed monitors in schema.yml — nest them under a model's meta block to keep monitor config next to the model it watches. See Embedded in dbt schema.yml.
  • Generate monitors from existing dbt tests — turn your unique, not_null, relationships, and singular tests into monitors automatically. See Generating monitors from dbt tests.

Project Configuration

Every MaC project needs a montecarlo.yml file in the project root:

FieldTypeRequiredDescription
versionintegeryesAlways 1. Currently the only supported version.
default_resourcestringconditionalWarehouse name or UUID. Required if multiple warehouses are configured. Find yours in Settings > Integrations > Warehouses and Lakes.
default_domainstringrecommendedDefault domain for monitors that don't specify domains. Effectively required — all new accounts need one domain per monitor.
namespacestringnoLogical grouping for monitors. When set here, takes precedence over --namespace CLI flag.
include_file_patternsarraynoGlob patterns for YAML files to scan. Default: **/*.yaml, **/*.yml.
exclude_file_patternsarraynoGlob patterns to skip.

# montecarlo.yml
version: 1
default_resource: my-snowflake
default_domain: my-domain

Where to put monitor definitions

Monitor definitions go in .yml files separate from montecarlo.yml. Two approaches:

Standalone YAML files — the standard approach. Place .yml files anywhere in your project directory. The CLI scans recursively. For dbt projects, place montecarlo.yml in the same directory as dbt_project.yml.

mac-project/
  montecarlo.yml        # project config only
  monitors/
    sales_checks.yml    # monitor definitions here
    pipeline_health.yml

Embedded in dbt schema.yml — nest monitors under a model's meta property to keep config next to the model it monitors. The meta key is required because dbt ignores unknown top-level properties. Use [[ ref('model_name') ]] for dbt ref resolution. Pass --dbt-manifest <path> when applying so the CLI can resolve refs — without it, the [[ ref() ]] string is passed through literally and the monitor will target an invalid table. See also: Generating monitors from dbt tests.

# models/schema.yml
version: 2

models:
  - name: orders
    meta:
      montecarlo:
        custom_sql:
          - name: orders_no_orphans
            description: "Orders must reference an existing customer"
            sql: |
              SELECT COUNT(*) FROM [[ ref('orders') ]]
              WHERE customer_id NOT IN (SELECT id FROM [[ ref('customers') ]])
            alert_conditions:
              - operator: GT
                threshold_value: 0
            schedule:
              type: fixed
              interval_minutes: 720
    columns:
      - name: order_id
        tests:
          - unique

You can also use [[ ref() ]] in standalone monitor files to reference dbt models:

data_source:
  table: "[[ref('orders')]]"

MaC uses [[ ]] instead of {{ }} to avoid conflicts with dbt's Jinja templating. The CLI resolves [[ ref('orders') ]] to the fully qualified table name (e.g., analytics:prod.orders) using the dbt manifest.

Monitor Types

MaC supports the same monitor categories as the Monte Carlo platform, including agent monitors.

CategoryYAML keyMonitorWhat it monitors
Table monitorstableTable MonitorFreshness, volume, and schema changes across many tables. ML-based anomaly detection.
Table monitorsjson_schemaJSON Schema MonitorStructural changes in a JSON/variant column.
Metric monitorsmetricMetric MonitorField-level and table-level statistical metrics over time. ML or fixed thresholds.
Metric monitorsmetric_comparisonMetric ComparisonMetric differences between a source and target table.
Metric monitorsbulk_monitorBulk MonitorField-level metrics across many tables via asset selection.
Validation monitorsvalidationValidation MonitorRow-level data quality rules (predicate trees).
Validation monitorscustom_sqlCustom SQL MonitorArbitrary SQL query result against a threshold.
Job monitorsjobJob MonitorFailures from Airflow, dbt, Databricks and other integrations.
Job monitorsquery_performanceQuery Performance MonitorQuery runtime regressions.
Agent monitorsagent_metricAgent Metric MonitorStatistical metrics over agent spans.
Agent monitorsagent_evaluationAgent Evaluation MonitorLLM-as-judge evaluation scores over agent outputs.
Agent monitorsagent_trajectoryAgent Trajectory MonitorSpan occurrence and relationship rules over an agent's trajectory.
Agent monitorsagent_validationAgent Validation MonitorRow-level validation rules over agent spans.

For deprecated types (freshness, volume, field_health, dimension_tracking, comparison, field_quality), see migration guides.

Deploying

🚧

PUT semantics — updates replace the entire definition.

When you modify a monitor in YAML and re-apply, every field not in the YAML resets to its default. Always include all fields you care about — not just the ones you're changing.

Compile

montecarlo monitors compile --namespace <namespace> [--project-dir <dir>]

Parses monitor YAML files and checks for syntax errors. Does not validate field names, values, or constraints — does not flag unknown or misspelled field names. Use check-jsonschema for structural validation or apply --dry-run for full validation. Useful as a fast first gate in CI pull-request checks (no API credentials required).

Apply Changes

montecarlo monitors apply --namespace <namespace> [--project-dir <dir>]

The apply command:

  1. Scans for all monitor YAML in the project (standalone and dbt-embedded)
  2. Creates new monitors, updates changed monitors, deletes removed monitors
  3. Scope is limited to the specified namespace — monitors in other namespaces are untouched

An apply is all-or-nothing for each namespace. A YAML syntax error in any file stops the CLI before anything is sent. If any monitor in a namespace fails validation, nothing in that namespace is created, updated, or deleted, and the output lists every monitor that failed validation so you can fix them together. If the apply fails partway through, that namespace's changes are rolled back. A run that covers several namespaces applies them one at a time, so namespaces applied before a failing one stay applied.

Dry Run

Preview what would change without applying:

montecarlo monitors apply --namespace <namespace> --dry-run
📘

Credit estimates in the plan

For consumption-based pricing accounts, the dry-run plan shows an estimated
daily credit cost per created or updated monitor, plus a per-namespace total,
so you can review cost before applying. Estimates are computed from the monitor
definition — no monitor runs — and are guidance, not a guarantee of billed
usage.

Some monitors can't be fully estimated ahead of time — for example, a
segmented monitor with no prior run history has no resolved segment count. In
those cases the estimate omits the segment multiplier and the namespace total
is shown as a lower bound (at least ~X); the real cost may be higher. A
monitor may also show no estimate at all (e.g. a type with no per-monitor credit
model), in which case it's simply excluded from the total.

Namespaces

A namespace is a string label that isolates a set of MaC-managed monitors — it has no configuration of its own and exists implicitly when you first apply to it. Each apply manages only its namespace — monitors from other namespaces are unaffected. This lets multiple teams, projects, or CI/CD pipelines manage monitors independently without interfering with each other.

Use cases:

  • Different teams manage monitors independently
  • Separate namespaces for dbt-managed vs standalone monitors
  • Isolate CI/CD pipelines that manage different monitor groups

Namespaces can be set via --namespace CLI flag, in montecarlo.yml, or per-monitor in the YAML. Namespaces are created implicitly on the first apply. Limit: 2,000 resources per namespace (CLI 0.52.0+). Each monitor and each notification channel counts as one. If an apply would leave a namespace with more than 2,000 resources, Monte Carlo rejects it with an error.

Moving monitors to another namespace

There's no command to rename a namespace, and changing a monitor's namespace in YAML creates a new monitor. To move monitors while keeping their UUIDs, incident history, and thresholds, convert them back to UI monitors and then into the new namespace:

montecarlo monitors convert-to-ui --namespace <old-namespace>
montecarlo monitors convert-to-mac --namespace <new-namespace> --monitors-file <file> --project-dir <dir>

convert-to-ui converts every monitor in the namespace. Both commands update the monitors in place, keep them running on their schedules, and accept --dry-run to preview the change. Run convert-to-mac once per target namespace, each time with a new namespace and a file listing the monitors that belong in it (see Converting UI monitors). Before you start, retire the old namespace's YAML and any CI job that applies it. Re-applying it would recreate the monitors as duplicates.

🚧

Shared namespace danger

Each apply replaces ALL monitors in the namespace. If two teams share a namespace, each deploy overwrites the other's monitors. Use separate namespaces per team or pipeline.

List existing namespaces and monitors:

montecarlo monitors namespaces              # list all namespaces
montecarlo monitors list --namespace <ns>   # list monitors in a namespace
🚧

Precedence: montecarlo.yml wins over --namespace.

When namespace is set in montecarlo.yml, it takes precedence over the --namespace CLI flag. The CLI prints a message noting that the project-file value is being used and the flag value ignored (e.g. namespace: <project-ns> found in montecarlo.yml ignoring value passed with --namespace=<flag-ns>). This is a common gotcha in CI/CD pipelines that pass --namespace expecting it to override the project file. Remove the namespace field from montecarlo.yml if you need the CLI flag to control namespace selection.

Delete a Namespace

Remove all monitors in a namespace:

montecarlo monitors delete --namespace <namespace>

CI/CD Integration

See the CI/CD Integration guide for GitHub Actions, GitLab CI, and CircleCI patterns.

The core pattern:

pip install montecarlodata
montecarlo monitors apply \
  --namespace ${NAMESPACE} \
  --project-dir ${PROJECT_DIR} \
  --auto-yes

The CLI reads MCD_DEFAULT_API_ID and MCD_DEFAULT_API_TOKEN from the environment — set them as CI secrets rather than assigning them on the command line.

Use --auto-yes only in CI to skip confirmation prompts.

More Information

Table Names

Write table names as they appear in Monte Carlo. Matching is case-sensitive. Monte Carlo can store a name in a different case from your warehouse: Snowflake, for example, reports identifiers in uppercase, and Monte Carlo stores them in lowercase.

Schema Validation

The published JSON Schema at https://clidocs.getmontecarlo.com/mac/schema.json can be used for structural validation of your YAML files. See Validation Tiers below.

Validation Tiers

Three levels of validation, from fastest to most thorough:

# 1. Syntax check (fastest, no credentials)
montecarlo monitors compile --namespace <namespace>

# 2. Structural validation (field names, types, enums — no API needed)
pip install check-jsonschema
check-jsonschema --schemafile https://clidocs.getmontecarlo.com/mac/schema.json monitors.yml

# 3. Full validation (semantic checks, table existence, metric names — requires API credentials)
montecarlo monitors apply --namespace <ns> --dry-run
📘

Schema validation limits

Tier 2 (check-jsonschema) uses a shared schema for all types. Per-type restrictions — crontab not supported on metric monitors, operator rejected on table monitors, loose schedule limited to json_schema — are only enforced at tier 3 (apply --dry-run). A YAML that passes tier 2 may still fail at deploy.

Default Field Stripping

Exported or previewed YAML (via --dry-run, the UI's Generate YAML button, or MCP tools) omits fields that match defaults. schedule.type: fixed and alert_conditions[].type: threshold won't appear because they're defaults. Both forms — compact and explicit — are valid input.

Exporting from the UI

Create a monitor in the UI, then use the Generate YAML button on the monitor details page to copy its definition into your codebase.

Export programmatically:

montecarlo monitors get-template --namespace <namespace> --project-dir <dir>
montecarlo monitors export-as-latest --namespace <namespace>

get-template writes a namespace's last-applied YAML to a new project directory. export-as-latest prints YAML in the latest format for legacy monitors that can be upgraded. It doesn't change your local files.

Converting UI Monitors

To bring existing UI monitors under MaC, use convert-to-mac:

montecarlo monitors convert-to-mac --namespace <namespace> --monitors-file <file> --project-dir <dir>

This moves the monitors into the namespace in place, keeping their UUIDs, incident history, and thresholds, and writes their YAML to --project-dir. There's no apply step: commit the generated YAML, and make future changes through it. Converted monitors can no longer be edited in the UI.

  • List the monitors to convert with --monitors-file (one UUID per line) or --monitor-uuids. Without either, every UI monitor in the account is converted.
  • --dry-run only writes the YAML. It converts nothing, so applying that YAML would create duplicates of the existing monitors rather than adopt them.
  • Use a namespace that isn't already managed as code. Converting into an existing MaC namespace doesn't add the monitors to that namespace's stored YAML. They become code-managed, but no apply updates them until you add their YAML to the namespace's files.

Try it on one or two monitors first.

After converting, keep each monitor's name the same in your YAML. Changing it creates a new monitor, and history doesn't carry over.

🚧

Deprecated types in exports

If your account has legacy monitors (e.g., field_health), convert-to-mac may export deprecated types that fail on re-apply. Review the exported YAML and migrate deprecated types (see migration guides) before running apply.

Code-managed monitors in the UI

  • They're locked in the UI. A banner explains that the monitor is managed by Monitors as Code, and you can't edit or delete it there. Make changes in YAML and apply them.
  • You can still pause them and run them on demand, for monitor types that support manual runs.
  • API edits are blocked or overwritten. Updating a code-managed monitor through the monitor-creation API is rejected. Other changes made through the API can succeed, but the next apply overwrites them.

Reference Pages

Troubleshooting

Reading apply errors

When apply fails validation, the CLI prints Errors encountered when attempting to apply configuration: followed by the errors for your configuration, then Error - Errors encountered, exiting. and Aborted!. That block is the cause of the failure. YAML syntax errors are listed under Configuration validation errors: instead, before anything is sent.

A warning such as Unknown enum value '<value>' for <Type>. This may indicate the SDK is out of date. Returning raw string value. doesn't cause a failure. The API returned a value newer than your installed SDK knows, and the SDK uses the raw value. Upgrading the CLI removes the warning but won't fix a failed apply.

Template apply timed out

During apply, the SQL in each custom SQL and validation monitor is checked against your warehouse. In a namespace with many of these monitors, the apply can run past its time limit and fail with Template apply timed out. To skip the check, add --no-sql-validation:

montecarlo monitors apply --namespace <namespace> --no-sql-validation

With the check off, invalid SQL isn't caught during the apply.

Can I run a dry run without permission to apply?

No. A dry run needs the same monitor management permission as a regular apply, so a user or API key without that permission can't run one.

Details and edge cases

Unexpected table errors with --create-non-ingested-tables. With this flag, apply accepts a table name it can't match instead of rejecting it, so a name in the wrong case surfaces later as a different error, such as the table not being in the monitor's domain. If you see an unexpected table error, check the name's case first.

convert-to-mac and an existing --project-dir. The directory passed to --project-dir must not exist yet. If it does, the command still converts the monitors, then stops without writing their YAML. To get the YAML, run get-template for the new namespace with a new --project-dir.


Did this page help you?