📝
Community-Driven Guide
Help improve this guide with your implementation experience

Clinical Quality Language (CQL) for FHIR Quality Measures

A comprehensive guide to implementing quality measures using CQL on FHIR, featuring breast cancer screening as a practical example

Introduction to CQL on FHIR

Clinical Quality Language (CQL) is a high-level, domain-specific language focused on clinical quality and is designed to be both human-readable and machine-processable. When combined with FHIR, CQL enables the expression of clinical knowledge in a way that can be executed against FHIR data sources.

Why CQL + FHIR?

  • Standardization: CQL provides a standard way to express clinical logic
  • Interoperability: Works seamlessly with FHIR data models
  • Quality Measures: Essential for eCQMs (electronic Clinical Quality Measures)
  • Clinical Decision Support: Enables sophisticated CDS rules

Key Components

CQL Libraries

Reusable collections of CQL expressions and functions

FHIR Resources

Patient data represented as FHIR resources (Patient, Observation, etc.)

Measure Resources

FHIR Measure resources that define quality measures

Example: Breast Cancer Screening Quality Measure

Let's explore a real-world example: measuring breast cancer screening rates. This is based on the CMS 125 measure - women ages 50-74 who had a mammogram within the past 27 months.

1. Measure Definition

Clinical Criteria:

  • Population: Women ages 50-74
  • Denominator: All women in the age range
  • Numerator: Women who had a mammogram in the past 27 months
  • Exclusions: Women with bilateral mastectomy, certain diagnoses

2. CQL Library Structure

library BreastCancerScreening version '1.0.0'

using FHIR version '4.0.1'

include FHIRHelpers version '4.0.1'
include MATGlobalCommonFunctions version '5.0.000' called Global

codesystem "LOINC": 'http://loinc.org'
codesystem "SNOMEDCT": 'http://snomed.info/sct'

valueset "Mammography": 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.108.12.1018'
valueset "Bilateral Mastectomy": 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.198.12.1005'

parameter "Measurement Period" Interval<DateTime>

context Patient

// Initial Population
define "Initial Population":
  Patient.gender = 'female'
    and AgeInYearsAt(start of "Measurement Period") >= 50
    and AgeInYearsAt(start of "Measurement Period") < 75

// Denominator
define "Denominator":
  "Initial Population"

// Numerator
define "Numerator":
  exists (
    [Observation: "Mammography"] Mammogram
      where Mammogram.status in { 'final', 'amended', 'corrected' }
        and Mammogram.effective during Interval[
          start of "Measurement Period" - 27 months,
          end of "Measurement Period"
        ]
  )

// Denominator Exclusions
define "Denominator Exclusions":
  exists (
    [Procedure: "Bilateral Mastectomy"] BilateralMastectomy
      where BilateralMastectomy.status = 'completed'
        and BilateralMastectomy.performed before end of "Measurement Period"
  )

3. FHIR Measure Resource

{
  "resourceType": "Measure",
  "id": "breast-cancer-screening",
  "url": "http://example.org/Measure/breast-cancer-screening",
  "version": "1.0.0",
  "name": "BreastCancerScreening",
  "title": "Breast Cancer Screening",
  "status": "active",
  "experimental": false,
  "date": "2025-01-01",
  "description": "Percentage of women 50-74 years of age who had a mammogram to screen for breast cancer",
  "purpose": "To measure the rate of breast cancer screening in eligible women",
  "scoring": {
    "coding": [{
      "system": "http://terminology.hl7.org/CodeSystem/measure-scoring",
      "code": "proportion",
      "display": "Proportion"
    }]
  },
  "type": [{
    "coding": [{
      "system": "http://terminology.hl7.org/CodeSystem/measure-type",
      "code": "process",
      "display": "Process"
    }]
  }],
  "improvementNotation": {
    "coding": [{
      "system": "http://terminology.hl7.org/CodeSystem/measure-improvement-notation",
      "code": "increase",
      "display": "Increased score indicates improvement"
    }]
  },
  "library": [
    "http://example.org/Library/BreastCancerScreening"
  ],
  "group": [{
    "population": [{
      "code": {
        "coding": [{
          "system": "http://terminology.hl7.org/CodeSystem/measure-population",
          "code": "initial-population"
        }]
      },
      "criteria": {
        "language": "text/cql",
        "expression": "Initial Population"
      }
    }, {
      "code": {
        "coding": [{
          "system": "http://terminology.hl7.org/CodeSystem/measure-population",
          "code": "denominator"
        }]
      },
      "criteria": {
        "language": "text/cql",
        "expression": "Denominator"
      }
    }, {
      "code": {
        "coding": [{
          "system": "http://terminology.hl7.org/CodeSystem/measure-population",
          "code": "numerator"
        }]
      },
      "criteria": {
        "language": "text/cql",
        "expression": "Numerator"
      }
    }, {
      "code": {
        "coding": [{
          "system": "http://terminology.hl7.org/CodeSystem/measure-population",
          "code": "denominator-exclusion"
        }]
      },
      "criteria": {
        "language": "text/cql",
        "expression": "Denominator Exclusions"
      }
    }]
  }]
}

4. Sample FHIR Data

Example patient data that would be evaluated by this measure:

// Patient Resource
{
  "resourceType": "Patient",
  "id": "patient-example",
  "gender": "female",
  "birthDate": "1968-03-15"
}

// Observation Resource (Mammogram)
{
  "resourceType": "Observation",
  "id": "mammogram-example",
  "status": "final",
  "code": {
    "coding": [{
      "system": "http://loinc.org",
      "code": "24604-1",
      "display": "Mammography"
    }]
  },
  "subject": {
    "reference": "Patient/patient-example"
  },
  "effectiveDateTime": "2024-06-15",
  "valueString": "Screening mammogram completed - no abnormalities detected"
}

Implementation Steps

Step 1: Set Up CQL Execution Engine

Choose and configure a CQL execution engine. Popular options include:

  • cql-execution: JavaScript-based CQL engine by MITRE
  • CQL Evaluator: Java-based engine integrated with HAPI FHIR
  • Clinical Quality Framework (CQF): Reference implementation
npm install cql-execution cql-exec-fhir

Step 2: Translate CQL to ELM

CQL must be translated to Expression Logical Model (ELM) JSON for execution:

npm install -g cql-to-elm
cql-to-elm --input BreastCancerScreening.cql --output BreastCancerScreening.json

Step 3: Execute Measure Evaluation

Use the $evaluate-measure operation on a FHIR server:

POST [base]/Measure/breast-cancer-screening/$evaluate-measure
Content-Type: application/fhir+json

{
  "resourceType": "Parameters",
  "parameter": [{
    "name": "periodStart",
    "valueDate": "2024-01-01"
  }, {
    "name": "periodEnd",
    "valueDate": "2024-12-31"
  }, {
    "name": "subject",
    "valueString": "Patient/patient-example"
  }, {
    "name": "reportType",
    "valueCode": "individual"
  }]
}

Step 4: Process MeasureReport

The server returns a MeasureReport resource with evaluation results:

{
  "resourceType": "MeasureReport",
  "status": "complete",
  "type": "individual",
  "measure": "http://example.org/Measure/breast-cancer-screening",
  "subject": {
    "reference": "Patient/patient-example"
  },
  "period": {
    "start": "2024-01-01",
    "end": "2024-12-31"
  },
  "group": [{
    "population": [{
      "code": {
        "coding": [{
          "code": "initial-population"
        }]
      },
      "count": 1
    }, {
      "code": {
        "coding": [{
          "code": "denominator"
        }]
      },
      "count": 1
    }, {
      "code": {
        "coding": [{
          "code": "numerator"
        }]
      },
      "count": 1
    }]
  }],
  "evaluatedResource": [{
    "reference": "Patient/patient-example"
  }, {
    "reference": "Observation/mammogram-example"
  }]
}

Best Practices

✓ Do's

  • ✅ Use standard value sets from VSAC (Value Set Authority Center)
  • ✅ Include version numbers in library declarations
  • ✅ Write comprehensive unit tests for CQL logic
  • ✅ Document clinical rationale for each criterion
  • ✅ Use FHIRPath expressions when possible
  • ✅ Leverage existing CQL libraries (MAT Global Common Functions)

✗ Don'ts

  • ❌ Hardcode codes instead of using value sets
  • ❌ Ignore data quality and completeness issues
  • ❌ Create overly complex nested logic
  • ❌ Skip validation against test patient data
  • ❌ Forget to handle missing or null data
  • ❌ Neglect performance optimization for large datasets

Testing & Validation

CQL Test Framework

The CQL Framework provides comprehensive testing capabilities:

Latest Testing Resources:

Example Test Case

{
  "name": "Patient Meets Numerator - Recent Mammogram",
  "description": "55-year-old female with mammogram 6 months ago should be in numerator",
  "patientData": {
    "resourceType": "Patient",
    "id": "test-patient-1",
    "gender": "female",
    "birthDate": "1969-01-01"
  },
  "observations": [{
    "resourceType": "Observation",
    "status": "final",
    "code": {
      "coding": [{
        "system": "http://loinc.org",
        "code": "24604-1"
      }]
    },
    "effectiveDateTime": "2024-06-01"
  }],
  "measurementPeriod": {
    "start": "2024-01-01",
    "end": "2024-12-31"
  },
  "expectedResults": {
    "initialPopulation": true,
    "denominator": true,
    "numerator": true,
    "denominatorExclusion": false
  }
}

Common CQL Patterns

Date Range Queries

define "Observations in Measurement Period":
  [Observation] O
    where O.effective during "Measurement Period"
      and O.status in { 'final', 'amended', 'corrected' }

Value Set Membership

define "Diabetes Diagnoses":
  [Condition: "Diabetes"] DiabetesCondition
    where DiabetesCondition.clinicalStatus ~ "active"
      and DiabetesCondition.verificationStatus ~ "confirmed"

Age Calculations

define "Patient Age at Start":
  AgeInYearsAt(start of "Measurement Period")

define "Eligible Age Range":
  "Patient Age at Start" >= 50 and "Patient Age at Start" < 75

Exists vs Count

// Use exists for boolean checks (more efficient)
define "Has Recent Lab":
  exists ([Observation: "Lab Test"] O where O.effective during "Recent Period")

// Use count when you need the actual number
define "Number of Encounters":
  Count([Encounter] E where E.period during "Measurement Period")

Additional Resources

Need Help Implementing CQL Quality Measures?

Our experts can help you design, implement, and validate CQL-based quality measures for your organization.