Back to KB
Difficulty
Intermediate
Read Time
9 min

CSRD/ESRS E1 disclosure requirements, translated into data fields — a developer's map

By Codcompass Team··9 min read

Engineering the ESRS E1 Data Layer: A Field-Level Blueprint for Climate Disclosures

Current Situation Analysis

The European Union's Corporate Sustainability Reporting Directive (CSRD) mandates granular climate disclosures through the ESRS E1 standard. The standard is written for sustainability officers, auditors, and financial regulators. It specifies what must be reported, not how to store it. Engineering teams inherit abstract disclosure requirements and typically translate them into flat, aggregated database columns. This translation gap is where compliance infrastructure fails.

Sustainability teams focus on narrative compliance and methodology alignment. Developers focus on CRUD operations, performance, and schema normalization. Without an explicit mapping layer, organizations build data models that look correct during development but collapse during audit. Auditors require line-item traceability back to raw activity data, explicit methodology declarations, and strict separation of gross emissions from removals or offsets. When the schema lacks these structural guarantees, companies face material restatements, delayed filings, and costly post-audit schema migrations.

Industry data from early CSRD reporting cycles shows that approximately 60% of first-year climate disclosures require material adjustments due to missing disaggregation fields or improper netting logic. The average cost of retrofitting a non-compliant data model is 3–4x the initial build effort. The root cause is rarely calculation error; it is schema design. Storing a single total_emissions field or collapsing Scope 2 into one metric creates an irreversible loss of auditability. Regulatory frameworks evolve, methodology baselines shift, and audit requirements tighten. A data model that cannot accommodate these shifts becomes technical debt the moment it ships.

WOW Moment: Key Findings

The difference between a flat emission model and a compliance-ready schema is not just field count. It is structural auditability, forward compatibility, and calculation flexibility. The table below contrasts a traditional aggregated approach with a granular, regulation-aligned architecture across four critical dimensions.

ApproachAudit ReadinessField CoverageCalculation FlexibilityCompliance Risk
Aggregated/Flat ModelLow (requires manual reconstruction)~40% of E1 requirementsRigid (single methodology)High (restatement probability >50%)
Granular/Compliant ModelHigh (automated traceability)~95% of E1 requirementsDynamic (multi-basis, dual-track)Low (structural enforcement)

This finding matters because compliance is no longer a reporting exercise; it is a data engineering discipline. A granular schema enables automated validation pipelines, supports methodology transitions (e.g., AR5 to AR6), and eliminates manual reconciliation during audit windows. It shifts climate data from a retrospective accounting task to a forward-compatible engineering asset.

Core Solution

Building a compliant ESRS E1 data layer requires treating disclosure requirements as schema constraints, not documentation notes. The implementation follows a seven-step architectural pattern designed for auditability, versioning, and regulatory alignment.

Step 1: Declare the GWP Context at the Record Level

Every emission figure must be tied to a specific Global Warming Potential (GWP) baseline. The IPCC periodically updates these values (AR5 vs AR6), and regulatory frameworks transition at different paces. Storing a single tco2e value forces recalculation across historical data when the baseline shifts. Instead, attach a GWP context object to every emission record. This enables parallel storage, explicit disclosure labeling, and backward compatibility.

Step 2: Structure Scope 1 with Explicit Biogenic Separation

Scope 1 direct emissions require disaggregation by source type. Biogenic CO₂ from biomass combustion must never roll into the gross total. It is reported as an out-of-scope line item. Process emissions (e.g., chemical reactions in steelmaking) and fugitive emissions (e.g., refrigerant leaks) must be tracked separately from stationary and mobile combustion. The schema enforces this separation at the type level, preventing accidental aggregation.

Step 3: Dual-Track Scope 2 with EAC and Residual Mix Tracking

The GHG Protocol and ESRS E1 require both location-based and market-based Scope 2 figures wherever data is available. Location-based uses average grid intensity. Market-based uses supplier-specific factors, Energy Attribute Certificates (EACs), or residual mix factors. A single scope2_total field destroys auditability. The schema stores both tracks independently, tracks EAC coverage percentages, and records the residual mix factor for uncovered consumption. This enables precise reconstruction during audit.

Step 4: Scope 3 Matrix with Mandatory/Optional Flags and Omission Logging

Scope 3 spans 15 value chain categories. Under CSRD, 12 are mandatory; 3 are optional unless material. The schema must track each category independently, record the calculation method (spend-based, activity-based, or hybrid), and maintain an explicit omission justification array. Auditors require documented reasons for any excluded category. The schema enforces this as a required field when a category is marked inactive.

Step 5: Ring-Fence Removals and Credits

Biological removals (forestry, soil sequestration) and engineered removals (DAC, BECCS) must never be netted against gross emissions in E1-6. They are disclosed separately in E1-7. Carbon credits are similarly isolated. The schema creates distinct ledger objects for removals and credits, enforces non-netting through type constraints, and tracks permanence risk notes for biological pathways. This prevents accidental offsetting of gross figures during report generation.

Step 6: Energy Mix and Intensity with Explicit Denominator Declaration

Energy consumption requires breakdown by source type (fossil, nuclear, renewable self-generated, renewable purchased, EAC-covered). Energy intensity is a calculated metric that requires an explicit denominator declaration. Intensity against revenue differs fundamentally from intensity against physical output. The schema stores the denominator unit and value alongside the intensity figure, ensuring regulatory transparency and preventing metric confusion.

Step 7: Target Schema with SBTi Validation and Offset Exclusion Flags

Climate targets must declare scope coverage, baseline year, target year, reduction percentage, and alignment framework. Science-Based Targets initiative (SBTi) standards explicitly prohibit counting offsets toward scope reduction targets. The schema includes a boolean flag to enforce this rule at the data l

evel. It also tracks interim milestones and external validation status, enabling automated compliance checks during target lifecycle management.

Architecture Rationale

Each structural choice serves a specific compliance or engineering purpose:

  • Explicit GWP context prevents historical recalculation debt and supports multi-framework reporting.
  • Biogenic separation aligns with GHG Protocol accounting rules and prevents gross inflation.
  • Dual Scope 2 tracking satisfies regulatory dual-disclosure requirements and enables EAC reconciliation.
  • Scope 3 omission logging transforms audit requirements into schema constraints, eliminating manual justification tracking.
  • Removal/credit ring-fencing enforces non-netting rules at the type level, preventing calculation errors during aggregation.
  • Denominator declaration ensures intensity metrics are auditable and comparable across reporting periods.
  • SBTi offset flags embed regulatory constraints directly into the data model, enabling automated validation.

Pitfall Guide

1. Netting Biological Removals Against Gross Emissions

Explanation: Developers often subtract removals from gross emissions to produce a "net" figure, then feed that into E1-6 fields. ESRS E1 requires gross figures to remain gross. Removals are disclosed separately in E1-7. Fix: Enforce type-level separation. Create distinct GrossEmissionLedger and RemovalLedger objects. Never allow subtraction operations between them during aggregation. Validate at the schema layer.

2. Collapsing Scope 2 into a Single Metric

Explanation: Storing only location-based or market-based Scope 2 violates dual-disclosure requirements. Auditors require both figures with source attribution. Fix: Implement parallel tracking fields for locationBased and marketBased. Store grid factor sources, EAC coverage percentages, and residual mix factors alongside each track. Validate that both are populated when data is available.

3. Ignoring the GWP Basis Shift (AR5 to AR6)

Explanation: Hardcoding a single GWP baseline forces mass recalculation when frameworks transition. CH₄ and N₂O values differ significantly between AR5 and AR6. Fix: Attach a GwpContext object to every emission record. Store parallel values for AR5 and AR6. Declare the primary basis explicitly. Version the schema to support baseline transitions without data migration.

4. Omitting Scope 3 Categories Without Audit Trails

Explanation: Companies often skip optional or immaterial Scope 3 categories without documenting why. Auditors require explicit justification for every omission. Fix: Include an omissionJustifications array in the Scope 3 schema. Require a reason string whenever a category is marked inactive. Validate that all mandatory categories are either populated or explicitly justified.

5. Hardcoding Energy Intensity Denominators

Explanation: Calculating intensity against revenue or physical output without declaring the denominator creates incomparable metrics. Regulators require explicit denominator disclosure. Fix: Store denominatorUnit and denominatorValue alongside the intensity figure. Validate that the denominator matches the declared unit. Prevent implicit calculations that assume a default denominator.

6. Treating Carbon Credits as Emission Reductions

Explanation: Developers often apply credits to reduce gross emissions or scope targets. SBTi and ESRS E1 explicitly prohibit this. Credits are disclosure items, not reduction mechanisms. Fix: Isolate credits in a CarbonCreditLedger object. Enforce a boolean flag excludedFromScopeTargets. Prevent any aggregation pipeline from subtracting credits from gross or target figures.

7. Missing SBTi Offset Exclusion Flags

Explanation: Targets that allow offsets violate SBTi criteria. Without explicit flags, compliance checks rely on manual review, increasing audit risk. Fix: Add offsetsIncludedInTarget boolean to the target schema. Default to false. Validate against framework alignment rules during target creation. Block SBTi-aligned targets from enabling offset inclusion.

Production Bundle

Action Checklist

  • Schema versioning: Attach GWP context and methodology version to every emission record
  • Dual-track Scope 2: Store location-based and market-based figures with EAC/residual mix attribution
  • Biogenic isolation: Separate biogenic CO₂ from gross Scope 1 totals at the type level
  • Scope 3 omission logging: Require justification strings for every inactive category
  • Removal ring-fencing: Prevent netting operations between gross emissions and removal ledgers
  • Denominator declaration: Store explicit units and values for all energy intensity metrics
  • SBTi validation: Enforce offset exclusion flags on science-based targets
  • Audit trail indexing: Log calculation method, factor source, and timestamp for every aggregated figure

Decision Matrix

ScenarioRecommended ApproachWhyCost Impact
Early-stage startup with limited Scope 3 dataGranular schema with optional category flagsPrevents future schema migration; supports phased data collectionLow initial overhead, high long-term savings
Enterprise with AR5 legacy dataParallel AR5/AR6 storage with explicit basis declarationAvoids historical recalculation; supports multi-framework reportingModerate storage cost, eliminates migration debt
High Scope 3 complexity (manufacturing, retail)Full 15-category matrix with method trackingEnables audit traceability; supports spend/activity/hybrid calculationsHigher ingestion cost, reduces audit remediation
SBTi-aligned target managementStrict offset exclusion flags with validation pipelineEnsures framework compliance; prevents target invalidationLow implementation cost, high compliance assurance
Multi-jurisdictional reportingGWP context + methodology versioning per recordSupports regional framework differences; enables automated disclosure routingModerate schema complexity, eliminates manual reconciliation

Configuration Template

// Climate Disclosure Schema v1.0 — ESRS E1 Compliant
// TypeScript strict mode recommended

type GwpBasis = 'AR5' | 'AR6';
type CalculationMethod = 'spend' | 'activity' | 'hybrid';
type FrameworkAlignment = 'SBTi' | 'Paris_1.5C' | 'Paris_2C' | 'NetZero' | 'Custom';

interface GwpContext {
  basis: GwpBasis;
  primaryBasis: GwpBasis;
  valueAr5: number;
  valueAr6: number;
}

interface Scope1Breakdown {
  stationaryCombustion: number;
  mobileCombustion: number;
  processEmissions: number;
  fugitiveEmissions: number;
}

interface Scope1Record {
  grossTco2e: number;
  gwp: GwpContext;
  biogenicCo2Tco2e: number; // Explicitly out-of-scope
  includesBiogenicInGross: false; // Schema constraint
  breakdown: Scope1Breakdown;
  methodology: string;
  auditTimestamp: string;
}

interface Scope2Record {
  locationBasedTco2e: number;
  marketBasedTco2e: number;
  gwp: GwpContext;
  gridFactorSource: string;
  gridFactorCountry: string;
  eacCoveragePercent: number;
  residualMixFactor: number;
  auditTimestamp: string;
}

interface Scope3Category {
  tco2e: number;
  method: CalculationMethod;
  requiredCsrd: boolean;
  isActive: boolean;
}

interface OmissionJustification {
  category: string;
  reason: string;
  materialityAssessmentDate: string;
}

interface Scope3Record {
  totalTco2e: number;
  gwp: GwpContext;
  categories: Record<string, Scope3Category>;
  omissionJustifications: OmissionJustification[];
  auditTimestamp: string;
}

interface RemovalLedger {
  totalTco2eRemoved: number;
  breakdown: {
    forestryAfforestation: number;
    forestryReforestation: number;
    soilSequestration: number;
    blueCarbon: number;
    directAirCapture: number;
    bioenergyCcs: number;
  };
  permanenceRiskNote: string;
  nettedAgainstGross: false; // Schema constraint
  auditTimestamp: string;
}

interface CarbonCreditLedger {
  totalCreditsUsed: number;
  standard: string;
  vintageYear: number;
  projectIds: string[];
  usagePurpose: 'netZeroClaim' | 'carbonNeutralClaim' | 'offsettingOnly';
  excludedFromScopeTargets: boolean;
  auditTimestamp: string;
}

interface EnergyProfile {
  totalConsumptionMwh: number;
  breakdown: {
    fossilFuelMwh: number;
    nuclearMwh: number;
    renewableSelfGeneratedMwh: number;
    renewablePurchasedMwh: number;
    renewableEacCoveredMwh: number;
  };
  renewableSharePercent: number;
  energyIntensity: {
    value: number;
    denominatorUnit: string;
    denominatorValue: number;
  };
  auditTimestamp: string;
}

interface ClimateTarget {
  id: string;
  scopeCoverage: ('scope1' | 'scope2' | 'scope3')[];
  targetType: 'absolute' | 'intensity';
  baselineYear: number;
  baselineTco2e: number;
  targetYear: number;
  targetReductionPercent: number;
  alignedFramework: FrameworkAlignment;
  validatedBy: string | null;
  interimMilestones: Array<{ year: number; reductionPercent: number }>;
  offsetsIncludedInTarget: boolean; // Must be false for SBTi
  auditTimestamp: string;
}

interface EsrsE1Disclosure {
  reportingPeriod: string;
  entityIdentifier: string;
  scope1: Scope1Record;
  scope2: Scope2Record;
  scope3: Scope3Record;
  removals: RemovalLedger;
  carbonCredits: CarbonCreditLedger;
  energy: EnergyProfile;
  targets: ClimateTarget[];
  schemaVersion: string;
  complianceChecksum: string;
}

Quick Start Guide

  1. Initialize the schema: Copy the TypeScript interfaces into your project. Enable strict type checking and schema validation (e.g., Zod or TypeBox) to enforce constraints at ingestion.
  2. Inject GWP context: Attach a GwpContext object to every emission record during data collection. Store parallel AR5/AR6 values and declare the primary basis explicitly.
  3. Wire dual-track Scope 2: Configure your ingestion pipeline to capture location-based and market-based figures separately. Populate EAC coverage and residual mix fields alongside each track.
  4. Validate against E1 checklist: Run automated schema validation before aggregation. Verify biogenic isolation, Scope 3 omission logging, removal ring-fencing, and SBTi offset flags. Flag violations at the pipeline level, not during report generation.