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
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.
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.
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 |