Fabric Ontology (preview): the item, its definition, and its bindings
An ontology is Fabric IQ's shared business vocabulary: entity types
(Customer), properties (email), and relationships
(Customer places Order), bound to real OneLake data so agents and
people reason in the same terms.
Item type name: Ontology — the metadata.type written into
.platform, so a Git-synced workspace serializes it as
<display name>.Ontology. Git integration lists it under "IQ (preview)
items" alongside Plan — not under Data Science or Real-Time
Intelligence, which is where people look first.
Everything below is preview, verified against the docs on 2026-09-02. Re-check before relying on a limit; this surface moves.
Not here, deliberately. The ontology graph is provided by Graph in
Microsoft Fabric — a
separate GraphModel item. GQL, graph-type DDL and executeQuery belong
to fabric-graph; this skill only carries the graph constraints that bite
at ontology time. Agent configuration belongs to fabric-data-agent
(conversational, ≤5 sources) and fabric-operations-agent (autonomous,
single-source) — ontology is one source for each of those.
The Git definition layout
Ontology definitions are JSON. Only the first two are required:
<Name>.Ontology/
.platform # metadata.type = "Ontology"
definition.json # REQUIRED, and literally {}
EntityTypes/{entityTypeId}/
definition.json # the entity type
DataBindings/{guid}.json # one file per binding
Documents/document{n}.json # {displayText, url}
Overviews/definition.json # preview-page widgets
ResourceLinks/definition.json # links to a Power BI report
RelationshipTypes/{relationshipTypeId}/
definition.json # source/target entityTypeId
Contextualizations/{guid}.json # binds the relationship to a table
Three things about the IDs, all of which surprise people reading a diff:
{entityTypeId}is a positive 64-bit integer, not a GUID — and it is a directory name. So is{relationshipTypeId}. GUID filenames appear one level down, forDataBindingsandContextualizations.- Property IDs are also bigints, and bindings reference them by
targetPropertyId. A binding file names no property names — onlysourceColumnName→targetPropertyId— so a diff of a binding is unreadable without the entity type'sdefinition.jsonopen beside it. definition.jsonat the root is an empty object. Do not "fix" it. The content all lives in the subdirectories.
Property valueType is one of String, Boolean, DateTime, Object,
BigInt, Double (plus Any for untyped properties). There is no
Decimal — see the trap below. Entity type and property name must
match ^[a-zA-Z][a-zA-Z0-9_-]{0,127}$; note the portal is stricter than
the API here and caps custom property names at 26 characters.
Full part-by-part schemas, including every field of a data binding and the Eventhouse variant, are in references/REFERENCE.md.
Generating an ontology from a semantic model
Generation creates the item, entity types from tables, static properties from columns, and relationship types from model relationships. What it does not do is bind time series data, review entity keys, or bind relationship types — all three are manual follow-ups, every time.
Support depends entirely on the semantic model's storage mode:
| Import | Direct Lake | DirectQuery | |
|---|---|---|---|
| Entity / property / relationship definitions | ✅ | ✅ | ✅ |
| Entity type bindings to data | ❌ | ✅ conditional | ❌ |
| Relationship type bindings | ❌ | ✅ conditional | ❌ |
| Querying through bindings | ❌ | ✅ (no measures or calculated columns) | ❌ |
This is the failure worth knowing. Direct Lake entity bindings work only when the backing lakehouse sits in a workspace with inbound public access enabled. When it does not, "the ontology item is created successfully but that entity type has no data bindings." A green checkmark and an empty ontology. Relationship bindings have their own condition: they generate only where a primary key is identified.
So an Import-mode model generates a correct-looking schema and nothing queryable, by design. Check the mode before blaming the data.
You also cannot generate from My workspace — move the semantic
model to a real workspace first.
The constraints that produce silent or confusing failures
- Managed lakehouse tables only. External tables that merely appear in a lakehouse are not supported, and the symptom is "entity type details shows no data" rather than an error at binding time.
- No OneLake security on the source lakehouse. A lakehouse with it enabled does not appear in the data-source picker at all — it looks like a permissions problem and is not.
- No delta column mapping. It is enabled automatically when column
names contain
,;{}()\n\t=or a space, and automatically on the delta tables backing import-mode semantic model tables. Symptom: the entity type details graph does not load. - Duplicate property names must share a type across entity types. A
string
IDon one and an integerIDon another is what makes entity types go missing from a generated ontology. - Renaming a source table after binding breaks it. Bindings carry
sourceTableNameas a string. - Refresh is manual. New rows upstream are invisible until the graph model is refreshed; a refresh schedule on the child Graph item is what shows up as capacity usage.
Verify these at the lakehouse, not in TMDL. A semantic model's TMDL
dataType is not the delta column type and the TMDL table name is not
the delta table name, so grepping TMDL for decimal or for spaced column
names produces false confidence in both directions. The check belongs on
the delta tables.
The Decimal trap, and its remedy
Fabric Graph does not support Decimal. Generate an ontology from a
model whose tables carry Decimal columns and those properties return
null on every query — no error, just nulls. Decimal is the natural
money type, so this hits currency columns first.
The remedy is documented and specific: recreate the property as
Double in the ontology and bind it to the source data. That works
because manual binding accepts a lakehouse decimal column as a source
for a double property — the type map is wider than the generator's
output. Full source-to-property type table in
references/REFERENCE.md; the one other trap in
it is that lakehouse decimal(p, s) maps to string, not double.
Binding data: the ordering and cardinality rules
- One static binding per entity type. You cannot union static data from two sources into one entity type. Static sources must be OneLake-backed.
- Many time-series bindings per entity type, from lakehouse and eventhouse sources together.
- Static first. A time-series binding needs an existing statically bound property to contextualize against, and the static value must exactly match a column in the time-series data.
- Entity type keys are
stringorintegeronly. One or more columns, together unique. - Time series data must be columnar — one row per timestamped observation.
Semantic enrichment is what makes agents work
Descriptions, synonyms, and key-value metadata on entity types and
properties. It is not decoration: the documented example is a data agent
that cannot answer "which ice cream shops sold the most frozen desserts?"
until Products gains the synonym frozen desserts.
Scope it honestly, because the docs do: enrichment helps the agent during schema exploration and reasoning, and query generation does not use the metadata directly. Only entity types support synonyms — properties and relationship types get descriptions and key-value pairs only, and keys must be unique within each object.
Consuming an ontology
Five paths, detailed in references/REFERENCE.md: Fabric operations agent (monitoring + actions), Fabric data agent (conversational Q&A), Foundry IQ agent, Copilot Studio agent, and custom agents over the ontology MCP server.
The last is the one that matters outside Fabric: an ontology is itself an MCP server, at
https://api.fabric.microsoft.com/v1/mcp/dataPlane/workspaces/<workspace-ID>/items/<ontology-item-ID>/ontologyEndpoint
Both IDs come out of the portal URL
(.../groups/<workspace-ID>/ontologies/<ontology-item-ID>). Note the
shape differs from the data agent's endpoint
(/v1/mcp/workspaces/{ws}/dataagents/{id}/agent) — dataPlane, items,
and a trailing ontologyEndpoint. It needs F2+ capacity and the
Ontology item (preview) tenant setting.
Two known agent behaviours worth carrying: a data agent's first few
queries after creation can fail while it initializes (wait, retry), and
aggregation is a known gap — add Support group by in GQL to the agent
instructions.
Before you start: tenant settings
Creating the item at all requires the Ontology item (preview) tenant setting. Failure to create a new ontology is most commonly this and not anything about your data. Data agent and operations agent each need their own settings on top.