GFR and albuminuria categories, and the 3-month persistence rule
Low filtering rate (below 60) on two results at least 90 days apart; otherwise say what is missing.
- Rule and version
kdigo_ckd_2024@1.1- Published source
- Kidney Disease: Improving Global Outcomes (KDIGO) CKD Work Group. KDIGO 2024 Clinical Practice Guideline for the Evaluation and Management of Chronic Kidney Disease. Kidney Int 2024;105(4S):S117-S314. Definition: abnormality of kidney structure or function present for more than 3 months; GFR categories G1-G5; albuminuria categories A1-A3. https://kdigo.org/guidelines/ckd-evaluation-and-management/
- Edition
- KDIGO 2024 CKD guideline (G/A categories, more than 3 months)
- Effective
- from 2026-11-12
- Role
- persistence phenotype and G/A category
- Status
- draft: encoded from the published source; not yet signed off by a clinical reviewer
- Clinical reviewer
- —
- Coding reviewer
- —
- Sponsor
- none
- Body hash
1a5087a17cd1b339f06da694dd8fcb92fe2f13fdbce57b886716763289bd95ad
Thresholds and parameters
{
"a_categories": [
[
"A3",
300.0001
],
[
"A2",
30
],
[
"A1",
0
]
],
"acr_threshold": 30,
"acute_change": "latest creatinine >= 1.5x the lowest value in the previous 365 days: 'possible acute change; repeat needed'",
"acute_change_lookback_days": 365,
"acute_change_ratio": 1.5,
"albuminuria_route": "eGFR >= 60 counts only with urine ACR >= 30 mg/g on two values >= 90 days apart and no ACR < 30 between them",
"classify_on": "eGFR rounded to report_decimals (what the screen shows)",
"egfr_threshold": 60,
"g_categories": [
[
"G1",
90
],
[
"G2",
60
],
[
"G3a",
45
],
[
"G3b",
30
],
[
"G4",
15
],
[
"G5",
0
]
],
"loinc_acr": "9318-7",
"not_assessable": "anything else: no steady-state value, one value below 60, values below 60 spanning fewer than 90 days, or values on both sides of 60 without persistence; never reported as 'not met'",
"not_met_requires": "two eGFR >= 60 at least 90 days apart with none < 60 between them, after the last value below 60",
"persistence": "at least two eGFR < 60 whose collection dates are >= 90 days apart, with no eGFR >= 60 between them; the persistent category is the less severe of the two qualifying values' G ranges (the range both values meet); the latest value's range is reported separately and is 'not confirmed' when worse",
"persistence_days": 90,
"steady_state_exclusion": "LOCAL CONVENTION: creatinine values from an inpatient encounter in which the KDIGO creatinine-change criteria are met under any baseline are excluded from staging, because eGFR equations assume a steady state",
"unstaged_or_g1_g2_statement": "with eGFR >= 60, a statement without a stage or at stage 1-2 needs kidney damage markers that this check does not read: not assessable, never 'not supported'"
}
Boundary tests: 9/9 pass
- pass · 59.9 twice, 91 days apart: expected {'status': 'met', 'stage': 'G3a'}, got {'status': 'met', 'stage': 'G3a'}
- pass · 59.9 twice, 89 days apart: expected {'status': 'not_assessable', 'reason_code': 'short_span'}, got {'status': 'not_assessable', 'reason_code': 'short_span'}
- pass · 55, 61, 50 over 200 days: expected {'status': 'not_assessable', 'reason_code': 'single_low'}, got {'status': 'not_assessable', 'reason_code': 'single_low'}
- pass · 47.6 then 28.1, 118 days: expected {'status': 'met', 'stage': 'G3a', 'latest_g': 'G4', 'latest_confirmed': False}, got {'status': 'met', 'stage': 'G3a', 'latest_g': 'G4', 'latest_confirmed': False}
- pass · 27.5 then 28.1, 95 days: expected {'status': 'met', 'stage': 'G4', 'latest_confirmed': True}, got {'status': 'met', 'stage': 'G4', 'latest_confirmed': True}
- pass · single value 48: expected {'status': 'not_assessable', 'reason_code': 'single_low'}, got {'status': 'not_assessable', 'reason_code': 'single_low'}
- pass · 72 and 68, 120 days: expected {'status': 'not_met'}, got {'status': 'not_met'}
- pass · one value 75: expected {'status': 'not_assessable', 'reason_code': 'normal_short'}, got {'status': 'not_assessable', 'reason_code': 'normal_short'}
- pass · no values: expected {'status': 'not_assessable', 'reason_code': 'no_values'}, got {'status': 'not_assessable', 'reason_code': 'no_values'}