build

What CQL is — and what engines actually execute

Updated 2026-07-27 · Level 2

Clinical Quality Language is the high-level language payers and measure stewards write so clinical logic can travel. Engines do not run that text — they run ELM, a verbose JSON tree. That one distinction is why a tool can read payer CQL without executing it.

What CQL hopes to achieve

Historically, "does this patient qualify for home oxygen?" lived inside each vendor's code, against each vendor's data model. CQL's ambition is a portable, human-readable, computable artifact: publish once, execute identically. It is an HL7 / ANSI-normative standard (cql.hl7.org). Canonical uses: quality measures (eCQMs), clinical decision support, computable guidelines, and public-health reporting. In the prior-auth loop you meet it at DTR — Documentation Templates and Rules — where a payer Questionnaire may carry a Library of CQL/ELM for prepopulation and gating.

CQL vs ELM vs FHIRPath

What it is Who reads it
CQL Human-authored source — define "Copd Diagnoses": [Condition: "COPD Diagnoses"] People
ELM Expression Logical Model — machine JSON/XML the engine walks Engines
FHIRPath Smaller navigation language over FHIR instances; related, not the same Both (SDC often uses it beside CQL)

The load-bearing fact: engines execute ELM, not CQL text. Compiling CQL→ELM is a separate step (Java reference translator, or a build-time service). ELM, being JSON, is also analyzable without any engine — which is the seam ImOnFHIR sits in today.

Where it attaches to FHIR

A Library resource carries text/cql and/or application/elm+json in content[]. A Questionnaire binds that Library with the cqf-library extension. SDC then hangs expressions on items: initialExpression (prefill), enableWhenExpression (gating richer than structural enableWhen), itemPopulationContext, calculatedExpression, candidateExpression. DTR's $questionnaire-package returns the Questionnaire plus the Libraries and ValueSets needed to complete it.

What ImOnFHIR does — and does not execute

In the FHIR Analysis Workbench DTR panel we:

  • Statically extract data requirements from ELM Retrieve nodes, from Library.dataRequirement[], and (downgraded) from a two-regex scan of CQL text — each result stamped with its provenance.
  • Evaluate only the declarative FHIR enableWhen operators and retrieve-presence against an optional data-context Bundle (three-valued; uncertainty never collapses to a silent false).
  • Do not execute CQL, ELM expressions, FHIRPath enableWhenExpression, or terminology $expand. Population is reported as "N declare population expressions," never as pre-populatable.

The UI chips say so out loud: not executed — statically extracted, and evaluated — … no CQL, FHIR Path expressions, or terminology executed.

That posture is a spec-sanctioned client position, not a shortfall: DTR requires population outcome completeness and permits alternative mechanisms to CQL execution for clients. (Payer servers have stronger obligations — Inferno's DTR kit checks them.) Futures that would run curated teaching CQL client-side are filed separately; this card stays present-tense about what ships today.

See also

CQL shows up in the Da Vinci education skeleton as a load-bearing topic beside SDC. The forms machinery that hosts those expressions is Structured Data Capture; dynamic answer lists that depend on earlier answers are parameterized value sets. For the ecosystem map around packages and validators, see the builder's field guide.

Go to the source