Semantic Layer: Eén Definitie voor Al Je Data

Gepubliceerd: 30 april 2026
Leestijd: 12 minuten
Data Engineering

Ontdek hoe een semantic layer zorgt voor consistente KPI's, minder shadow IT en snellere inzichten voor je hele organisatie.

Wat is een Semantic Layer en Waarom is het Relevant in 2026?

Stel je voor: het sales-team berekent "omzet" door alle gefactureerde bedragen op te tellen, terwijl finance alleen de daadwerkelijk ontvangen betalingen meetelt. De marketingafdeling gebruikt weer een derde definitie die kortingen uitsluit. Drie teams, drie dashboards, drie antwoorden op dezelfde vraag. Dit is het klassieke probleem dat een semantic layer oplost.

Een semantic layer is een abstractielaag tussen je ruwe data en de mensen (of tools) die die data consumeren. Het is de plek waar je één keer definieert wat "omzet", "actieve klant" of "churn rate" betekent — en die definitie vervolgens consistent uitserveer aan alle BI-tools, data-apps en API-consumers in je organisatie.

Definitie: Semantic Layer

Een semantic layer (ook wel metrics layer of headless BI genoemd) is een gecentraliseerde laag in je data-architectuur die business logica, KPI-definities, dimensies en metrics vertaalt naar een consistente, tool-agnostische interface. De laag staat tussen je data warehouse (of lakehouse) en je consumptielaag.

Waarom is dit in 2026 meer relevant dan ooit?

De data-stack is de afgelopen jaren enorm gefragmenteerd. Een gemiddelde organisatie gebruikt Tableau én Power BI, heeft Looker-dashboards naast zelf-gebouwde data-apps, en integreert real-time AI-assistenten die direct SQL schrijven op het warehouse. Zonder een semantic layer eindigt elk van deze tools met zijn eigen versie van de waarheid.

Exploderend tool-landschap

Organisaties gebruiken gemiddeld 4–6 BI- en analytics-tools tegelijk. Zonder centrale logica wordt elke integratie een kopie-paste-nachtmerrie.

AI-gegenereerde SQL

LLM-tools schrijven zelfstandig queries. Zonder semantische context schrijven ze foute berekeningen die er goed uitzien maar verkeerde resultaten geven.

Data governance & compliance

Één plek voor business logica maakt auditing, lineage-tracking en access control aanzienlijk eenvoudiger — cruciaal voor AVG-compliance en SOC2.

Hoe Werkt een Semantic Layer?

Een semantic layer bestaat uit een aantal bouwblokken die samen de brug vormen tussen fysieke data en business begrippen. Hieronder zie je hoe de architectuur in elkaar steekt.

De drie lagen van een moderne data-stack met semantic layer

1

Storage & Processing Layer

Je data warehouse of lakehouse: Snowflake, BigQuery, Databricks, DuckDB. Hier liggen de ruwe en getransformeerde tabellen. De semantic layer leest hier data vandaan, maar schrijft er niets naar terug.

2

Semantic Layer

Hier definieer je metrics, dimensies, joins en access control in code of configuratie. Tools zoals dbt Semantic Layer, Cube.dev of AtScale vertalen inkomende queries naar geoptimaliseerde SQL en cachen resultaten waar nodig.

3

Consumptie Layer

BI-tools (Tableau, Power BI, Metabase), notebooks (Jupyter), data-apps, REST/GraphQL API's en AI-assistenten connecten via een standaard interface (JDBC, GraphQL, REST) op de semantic layer — zonder directe toegang tot het warehouse.

Kernbegrippen uitgelegd

Concept Wat is het? Voorbeeld
Metric Een berekende KPI met één officiële definitie revenue = SUM(order_amount) WHERE status = 'paid'
Dimension Een attribuut om metrics te segmenteren Regio, klantsegment, productcategorie
Entity Het primaire object waarop metrics zijn gebaseerd Order, klant, sessie
Measure Een aggregeerbare waarde vóór business logica COUNT(DISTINCT user_id)
Semantic Model De volledige beschrijving van een data-object inclusief joins, measures en dimensies Orders model met relaties naar customers en products

Praktische Codevoorbeelden

We bekijken drie van de meest gebruikte tools voor semantic layers: dbt Semantic Layer, Cube.dev en AtScale. Elk heeft zijn eigen filosofie en syntax.

1. dbt Semantic Layer (MetricFlow)

Sinds dbt versie 1.6 is MetricFlow de officiële semantic layer van dbt. Je definieert semantic_models en metrics in YAML-bestanden naast je bestaande dbt-modellen.

# models/semantic_models/orders.yml
semantic_models:
  - name: orders
    description: "Semantisch model voor bestellingen"
    model: ref('fct_orders')
    
    entities:
      - name: order
        type: primary
        expr: order_id
      - name: customer
        type: foreign
        expr: customer_id
    
    dimensions:
      - name: order_status
        type: categorical
        expr: status
      - name: order_date
        type: time
        type_params:
          time_granularity: day
        expr: created_at
      - name: region
        type: categorical
        expr: shipping_region
    
    measures:
      - name: order_count
        description: "Totaal aantal orders"
        agg: count
        expr: order_id
      - name: revenue
        description: "Gefactureerde omzet (excl. BTW)"
        agg: sum
        expr: order_amount_excl_vat
      - name: avg_order_value
        description: "Gemiddelde orderwaarde"
        agg: average
        expr: order_amount_excl_vat

---
# models/metrics/revenue_metrics.yml
metrics:
  - name: monthly_revenue
    description: "Maandelijkse omzet van betaalde orders"
    type: simple
    label: "Maandelijkse Omzet"
    type_params:
      measure: revenue
    filter: |
      {{ Dimension('order__order_status') }} = 'paid'

  - name: revenue_growth_mom
    description: "Maand-over-maand omzetgroei in procenten"
    type: derived
    label: "Omzetgroei MoM (%)"
    type_params:
      expr: (revenue_this_month - revenue_last_month) / revenue_last_month * 100
      metrics:
        - name: monthly_revenue
          alias: revenue_this_month
        - name: monthly_revenue
          alias: revenue_last_month
          offset_window: 1 month

  - name: active_customers
    description: "Unieke klanten met minstens 1 betaalde order"
    type: simple
    label: "Actieve Klanten"
    type_params:
      measure:
        name: order_count
        filter: |
          {{ Dimension('order__order_status') }} = 'paid'
    type_params:
      measure: customer_count

Je kunt deze metrics opvragen via de dbt CLI of de Semantic Layer API:

# Query via dbt CLI (lokale ontwikkeling)
dbt sl query \
  --metrics monthly_revenue,active_customers \
  --group-by order__order_date__month,order__region \
  --where "order__order_date__month >= '2025-01-01'" \
  --order-by order__order_date__month

# Output (voorbeeld):
# order_date_month | region    | monthly_revenue | active_customers
# 2025-01          | Noord-NL  | 124500.00       | 342
# 2025-01          | Zuid-NL   | 98200.00        | 289
# 2025-02          | Noord-NL  | 131200.00       | 367

2. Cube.dev — Headless BI Platform

Cube.dev positioneert zich als een volledig headless BI-platform met een krachtige cachinglaag (pre-aggregations) en een REST/GraphQL API. Ideaal als je data-apps wilt bouwen bovenop je warehouse.

// cube.js — Orders cube definitie
cube('Orders', {
  sql: `SELECT * FROM analytics.fct_orders`,
  
  // Joins naar andere cubes
  joins: {
    Customers: {
      sql: `${Orders}.customer_id = ${Customers}.customer_id`,
      relationship: 'many_to_one'
    },
    Products: {
      sql: `${Orders}.product_id = ${Products}.product_id`,
      relationship: 'many_to_one'
    }
  },

  // Measures = de KPI's
  measures: {
    revenue: {
      sql: `order_amount_excl_vat`,
      type: 'sum',
      description: 'Omzet excl. BTW, alleen betaalde orders',
      filters: [{ sql: `${CUBE}.status = 'paid'` }],
      format: 'currency'
    },
    orderCount: {
      sql: `order_id`,
      type: 'count',
      description: 'Totaal aantal orders'
    },
    avgOrderValue: {
      sql: `order_amount_excl_vat`,
      type: 'avg',
      description: 'Gemiddelde orderwaarde',
      format: 'currency'
    },
    activeCustomers: {
      sql: `customer_id`,
      type: 'countDistinct',
      filters: [{ sql: `${CUBE}.status = 'paid'` }],
      description: 'Unieke betalende klanten'
    }
  },

  // Dimensies = segmentatie-attributen
  dimensions: {
    orderId: {
      sql: `order_id`,
      type: 'number',
      primaryKey: true
    },
    status: {
      sql: `status`,
      type: 'string'
    },
    region: {
      sql: `shipping_region`,
      type: 'string'
    },
    createdAt: {
      sql: `created_at`,
      type: 'time'
    }
  },

  // Pre-aggregations voor snelheid
  preAggregations: {
    monthlyRevenue: {
      measures: [revenue, activeCustomers],
      dimensions: [region],
      timeDimension: createdAt,
      granularity: 'month',
      refreshKey: { every: '1 hour' }
    }
  }
});

Cube.dev serveert automatisch een REST API die je vanuit elke tool kunt aanspreken:

// REST API call vanuit een React data-app
const response = await fetch('/cubejs-api/v1/load', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${CUBE_API_TOKEN}`
  },
  body: JSON.stringify({
    query: {
      measures: ['Orders.revenue', 'Orders.activeCustomers'],
      dimensions: ['Orders.region'],
      timeDimensions: [{
        dimension: 'Orders.createdAt',
        granularity: 'month',
        dateRange: ['2025-01-01', '2025-12-31']
      }],
      order: { 'Orders.createdAt': 'asc' }
    }
  })
});

const data = await response.json();
// { data: [{ "Orders.region": "Noord-NL", 
//            "Orders.revenue": "124500.00",
//            "Orders.activeCustomers": "342", ... }] }

3. AtScale — Enterprise Semantic Layer

AtScale richt zich op grote enterprise-omgevingen met complexe Snowflake/Databricks-deployments en native integratie met Excel, Power BI en Tableau via MDX/DAX.

# AtScale semantic model (YAML export)
semantic_model:
  name: "Sales Analytics"
  warehouse: snowflake_production
  
  datasets:
    - name: orders_dataset
      sql: |
        SELECT 
          o.order_id,
          o.customer_id,
          o.order_amount_excl_vat,
          o.status,
          o.created_at,
          c.region,
          c.segment
        FROM fct_orders o
        JOIN dim_customers c ON o.customer_id = c.customer_id
        WHERE o.created_at >= '2024-01-01'

  metrics:
    - name: Revenue
      display_name: "Omzet (Betaald)"
      dataset: orders_dataset
      expression: "SUM(order_amount_excl_vat)"
      filter: "status = 'paid'"
      format: "€#,##0.00"
      
    - name: ActiveCustomers  
      display_name: "Actieve Klanten"
      dataset: orders_dataset
      expression: "COUNT(DISTINCT customer_id)"
      filter: "status = 'paid'"

  hierarchies:
    - name: Geography
      levels:
        - name: Region
          column: region
        - name: CustomerSegment
          column: segment

  access_control:
    - role: sales_manager
      allowed_dimensions: [Geography]
      row_filter: "region = '${user_region}'"

Vergelijking: Welke Tool Kies Je?

De keuze tussen semantic layer-oplossingen hangt sterk af van je bestaande stack, teamgrootte en use cases. Hier een overzicht van de meest gebruikte opties in 2026:

Tool Ideaal voor Sterktes Beperkingen Pricing
dbt Semantic Layer Teams die al dbt gebruiken Naadloze dbt-integratie, version control, Python-support Vereist dbt Cloud (betaald), beperkte caching Onderdeel dbt Cloud Team/Enterprise
Cube.dev Data-app developers, API-first teams Krachtige pre-aggregations, REST + GraphQL, self-hosted mogelijk Leercurve, eigen query-taal (Cube Query Format) Open source + cloud vanaf $250/mnd
AtScale Enterprise met Power BI / Excel MDX/DAX-support, row-level security, multi-warehouse Prijzig, complexe setup, minder developer-friendly Enterprise pricing (op aanvraag)
Looker (LookML) Organisaties all-in op Google Cloud Volwassen platform, uitgebreide permissies, embedded analytics Vendor lock-in, hoge licentiekosten, eigen BI-tool Enterprise pricing
Lightdash dbt-teams die open source BI willen Gratis, self-hosted, leest dbt YAML direct Beperktere enterprise-features, kleinere community Open source / cloud vanaf $400/mnd

Aanbeveling voor 2026

Voor de meeste moderne data engineering teams is dbt Semantic Layer + Cube.dev de sweet spot: dbt voor transformaties en metric-definities, Cube als serving-laag voor data-apps en API-consumers. Ben je een klein team met een beperkt budget? Start dan met alleen de dbt Semantic Layer — die geeft je al 80% van de voordelen zonder extra infrastructuur.

Praktijkvoorbeeld: E-commerce Bedrijf

Case: Nederlandse Webshop met 12 Dashboards en 3 Versies van "Omzet"

Situatie: Een Nederlandse e-commerce speler met €50M+ omzet had dashboards in Tableau, Power BI én een zelfgebouwde React-app. Het finance-team rapporteerde andere omzetcijfers dan het sales-team, omdat Tableau de valutaconversie op transactiedatum deed terwijl Power BI de rapportagedatum gebruikte.

Oplossing: Implementatie van dbt Semantic Layer met één definitie van revenue_eur — altijd in euro's op transactiedatum, altijd exclusief BTW, altijd alleen status = 'paid'. Alle tools connecten nu via de Semantic Layer API.

Resultaat: Van 3 versies naar 1 versie van de waarheid. Onboarding van nieuwe BI-tools gaat van 3 weken naar 2 dagen. De AI-assistent (gebaseerd op GPT-4o) schrijft nu semantisch correcte queries omdat hij de metric-definities als context meekrijgt.

Best Practices en Production Tips

Een semantic layer implementeren is één ding — hem goed laten werken in productie is een tweede. Hier zijn de lessen die we hebben geleerd uit real-world deployments.

1. Begin met metrics, niet met dimensies

De verleiding is groot om alles tegelijk te modelleren. Begin in plaats daarvan met de 5–10 KPI's die het meest worden betwist in je organisatie. Zodra het team ziet dat iedereen dezelfde cijfers ziet, groeit het draagvlak vanzelf.

2. Behandel je semantic layer als code

# .github/workflows/semantic-layer-ci.yml
name: Semantic Layer CI

on:
  pull_request:
    paths:
      - 'models/semantic_models/**'
      - 'models/metrics/**'

jobs:
  validate-metrics:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup dbt
        run: pip install dbt-core dbt-snowflake
      
      - name: Validate semantic models
        run: |
          dbt parse
          dbt sl validate-configs
        env:
          DBT_SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
          DBT_SNOWFLAKE_PASSWORD: ${{ secrets.SNOWFLAKE_PASSWORD }}
      
      - name: Test metrics (smoke test)
        run: |
          dbt sl query \
            --metrics revenue,active_customers \
            --group-by order__order_date__month \
            --limit 5

3. Documenteer de business logica expliciet

# Goede metric-definitie: uitlegbaar voor iedereen
metrics:
  - name: monthly_recurring_revenue
    label: "MRR (Monthly Recurring Revenue)"
    description: |
      Maandelijks terugkerende omzet van actieve abonnementen.
      
      Definitie (vastgesteld door Finance op 2025-03-15):
      - Inclusief: alle actieve subscription-orders (status = 'active')
      - Exclusief: eenmalige aankopen, setup fees, BTW
      - Valuta: altijd EUR op transactiedatum
      - Owner: finance@bedrijf.nl
      
      NIET te verwarren met:
      - Total Revenue (bevat ook eenmalige aankopen)
      - ARR (= MRR * 12, apart gedefinieerd)
    type: simple
    type_params:
      measure: subscription_amount
    filter: |
      {{ Dimension('order__order_status') }} = 'active'
      AND {{ Dimension('order__order_type') }} = 'subscription'

4. Gebruik pre-aggregations strategisch

Voor hoog-frequente queries op grote datasets zijn pre-aggregations essentieel. Definieer ze voor de meest voorkomende combinaties:

// cube.js — Strategische pre-aggregations
preAggregations: {
  // Dagelijkse KPI-summary voor executive dashboards
  dailyExecutiveSummary: {
    measures: [revenue, activeCustomers, orderCount],
    dimensions: [region],
    timeDimension: createdAt,
    granularity: 'day',
    partitionGranularity: 'month',
    refreshKey: { every: '1 hour' },
    buildRangeStart: { sql: `SELECT DATEADD('day', -90, NOW())` },
    buildRangeEnd:   { sql: `SELECT NOW()` }
  },
  
  // Realtime last-hour voor operationele monitoring
  realtimeHourly: {
    measures: [orderCount, revenue],
    timeDimension: createdAt,
    granularity: 'minute',
    refreshKey: { every: '1 minute' },
    buildRangeStart: { sql: `SELECT DATEADD('hour', -2, NOW())` },
    buildRangeEnd:   { sql: `SELECT NOW()` }
  }
}

5. Implementeer semantic access control

Een semantic layer is de ideale plek voor row-level en column-level security — één keer gedefinieerd, overal gehandhaafd:

// cube.js — Contextuele row-level security
queryRewrite: (query, { securityContext }) => {
  // Sales managers zien alleen hun eigen regio
  if (securityContext.role === 'regional_manager') {
    return {
      ...query,
      filters: [
        ...query.filters,
        {
          member: 'Orders.region',
          operator: 'equals',
          values: [securityContext.region]
        }
      ]
    };
  }
  
  // Finance ziet alles
  if (securityContext.role === 'finance') {
    return query;
  }
  
  // Default: geen toegang
  throw new Error('Insufficient permissions');
}

Veelgemaakte Fouten om te Vermijden

  • Alles in één keer migreren: Migreer incrementeel, begin met 1–2 kritische metrics.
  • Geen eigenaarschap: Wijs een metric owner aan per KPI — anders veroudert de definitie snel.
  • Performance vergeten: Een semantic layer zonder caching kan je warehouse juist overbelasten. Meet altijd query-kosten voor en na.
  • BI-tools te vroeg disconnecten: Laat legacy dashboards naast de semantic layer draaien tot je zeker bent van data-pariteit.

Conclusie: Wanneer Wel en Wanneer Niet?

Een semantic layer is geen silver bullet — maar voor de juiste organisatie is het een van de meest impactvolle investeringen in je data-architectuur.

Situatie Advies Reden
✅ Meerdere BI-tools in gebruik Zeker implementeren Voorkomt metric-inconsistentie tussen tools
✅ Data-apps bouwen bovenop warehouse Zeker implementeren Cube.dev/dbt API maakt dit tien keer eenvoudiger
✅ AI-assistenten die SQL schrijven Zeker implementeren Semantische context verbetert LLM-nauwkeurigheid drastisch
✅ Enterprise met compliance-vereisten Zeker implementeren Gecentraliseerde access control en lineage
⚠️ Klein team, 1 BI-tool, stabiele metrics Overweeg het Vo