FlureeLabs

Reasoning and Inference

Fluree includes a built-in reasoning engine that can derive new facts from your data based on ontology declarations (RDFS and OWL) or user-defined rules (Datalog). This page introduces the core concepts; see Query-time reasoning for usage syntax, Datalog rules for custom rules, and the OWL & RDFS reference for a full list of supported constructs.

Status: Reasoning is an experimental feature. See Standards and feature flags for how to enable it.

Why reasoning?

In a plain triple store every fact must be stated explicitly. If you assert that Alice is a Student and that Student is a subclass of Person, a query for all Person instances will not return Alice — unless you also assert Alice rdf:type Person.

With reasoning enabled, Fluree can infer the missing fact automatically:

Alice  rdf:type  Student       (asserted)
Student  rdfs:subClassOf  Person   (schema)
────────────────────────────────────────────
Alice  rdf:type  Person        (inferred)

This keeps your data clean (no redundant assertions) while giving your queries the full power of schema-aware retrieval.

Reasoning modes

Fluree supports four reasoning profiles that can be enabled independently or in combination. They are listed here from lightest to most powerful:

ModeWhat it doesCost
RDFSExpands rdfs:subClassOf and rdfs:subPropertyOf hierarchies so that querying for a superclass or superproperty also returns instances of its subclasses/subproperties.Very low — query rewriting only, no materialization.
OWL 2 QLEverything RDFS does, plus owl:inverseOf expansion and rdfs:domain/rdfs:range type inference via query rewriting. Based on the OWL 2 QL profile designed for query answering.Low — query rewriting only.
OWL 2 RLForward-chaining materialization of a comprehensive rule set (symmetric, transitive, and inverse properties; functional properties; property chains; class restrictions; owl:sameAs equivalence; and more). See the OWL & RDFS reference for the full list.Medium — derives facts before query execution; results are cached.
DatalogUser-defined if/then rules expressed in a familiar JSON-LD pattern syntax. Rules run in a fixpoint loop and can chain off each other or off OWL-derived facts. See Datalog rules.Depends on the rules — can be lightweight or heavy.

Combining modes

Modes can be combined freely. For example, ["rdfs", "owl2rl", "datalog"] first materializes OWL 2 RL entailments, then runs your Datalog rules over the combined base + OWL-derived data, and finally applies RDFS query rewriting on top. This layering lets you start simple (RDFS) and add more powerful inference only where you need it.

How it works

Fluree uses two complementary techniques depending on the mode:

Query rewriting (RDFS, OWL 2 QL)

The query planner rewrites your patterns at compile time. For example, a ?x rdf:type ex:Person pattern is expanded into a UNION over Person and all of its subclasses. No extra data is stored; the rewriting is transparent to the caller.

Forward-chaining materialization (OWL 2 RL, Datalog)

Before your query runs, the engine:

  1. Loads the ontology — extracts OWL/RDFS declarations (property types, class hierarchies, restrictions) from your data.
  2. Applies rules in a fixpoint loop — each iteration derives new facts from the combination of asserted and previously-derived facts. The loop stops when no new facts are produced (fixpoint) or a budget limit is reached.
  3. Overlays derived facts — the inferred triples are layered on top of your base data as a read-only overlay. Your original data is never modified.
  4. Caches the result — if the same database state is queried again with the same reasoning modes, the cached materialization is reused instantly.

Budget controls

To guarantee termination, materialization enforces configurable limits:

LimitDefaultWhat happens when exceeded
Time30 secondsMaterialization stops; partial results used
Derived facts1,000,000Materialization stops; partial results used
Memory100 MBMaterialization stops; partial results used

When a budget is exceeded the query still runs — it simply uses whatever facts were derived before the limit was hit. Diagnostics are available via tracing spans to identify when capping occurs.

Enabling reasoning

There are two levels of control:

1. Ledger-wide defaults (configuration graph)

Set reasoning defaults so every query against a ledger uses a particular mode without having to specify it each time:

{
  "@context": {"f": "https://ns.flur.ee/db#"},
  "insert": {
    "@id": "urn:fluree:mydb:main:config:ledger",
    "@type": "f:LedgerConfig",
    "f:reasoningDefaults": {
      "f:reasoningModes": {"@id": "f:RDFS"},
      "f:overrideControl": {"@id": "f:OverrideAll"}
    }
  }
}

See Setting groups — reasoningDefaults for full configuration options.

2. Per-query override

Any query can specify or override the reasoning mode:

{
  "select": ["?s"],
  "where": {"@id": "?s", "@type": "ex:Person"},
  "reasoning": "rdfs"
}

Use "reasoning": "none" to explicitly disable reasoning for a single query, even if the ledger has defaults configured.

See Query-time reasoning for complete syntax and examples.

Key concepts

Schema as data

Unlike systems with external schema files, Fluree stores ontology declarations as regular triples in your graph. An rdfs:subClassOf assertion is just another triple — you add it via a normal transaction:

{
  "@context": {
    "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
    "ex": "http://example.org/"
  },
  "insert": {
    "@id": "ex:Student",
    "rdfs:subClassOf": {"@id": "ex:Person"}
  }
}

This means your schema evolves with your data, is time-travelable, and is subject to the same policy controls as any other data.

Derived facts are virtual

Inferred triples exist only in a query-time overlay — they are never written to storage. This means:

  • No storage bloat — you don't pay disk costs for derived facts.
  • Always consistent — derived facts are recomputed from the current state, so they can never go stale.
  • Time-travel safe — querying a historical point in time materializes based on that point's data and schema.

owl:sameAs and identity

When OWL 2 RL is enabled, the engine tracks owl:sameAs equivalences using an efficient union-find data structure. If two resources are determined to be the same (via functional properties, inverse functional properties, or owl:hasKey), all their facts are merged under a canonical representative. Queries transparently resolve through these equivalences.

What to read next

TopicPage
Using reasoning in queriesQuery-time reasoning
Writing custom inference rulesDatalog rules
Full list of supported OWL & RDFS constructsOWL & RDFS reference
Configuring ledger-wide defaultsSetting groups