Skip to main content
This is 2026.9 documentation. Coverage here is incremental: a page exists only where 2026.9 differs or is newly documented. For any other topic, switch to Current (2026.8 and earlier) in the version selector.
Before 2026.9, as the Data Schema describes, overlapping membership is a Proxy at the Root Collection: a material, level, group, or definition lists applicationIds in objects. Hierarchy is a tree you walk through Collection.elements. 2026.9 replaces that reconstruction with an explicit relational layer: typed, directed edges between objects (and, where needed, structural nodes such as a level, material, or grouping container). For the two-store picture, see Object model in 2026.9. Dates and who must act are on Data model migration for developers. Proxies themselves do not exist in 2026.9 bundle data - there is no RenderMaterial, Level, Group, Definition, InstanceProxy, or InstanceDefinitionProxy object anywhere in the format. The relation types below are what carries that information instead.

Why relations exist

Proxies let one object participate in several organizations without copying geometry. They do not encode connectivity, hosting, or room occupancy as a graph a consumer can query. 2026.9 keeps the “no duplication” rule and makes those links first-class, which is what lets Speckle Intelligence answer topology questions instead of only looking up properties on each object. Rooms and MEP spaces that carry geometry are objects in this layer, not grouping nodes. A furniture item’s room membership is a relation to that room object (IN_ROOM), not a Proxy list on a container.

Relation types you will see

Names below are the live vocabulary of the relational layer (the same names the 2026.9 viewer inspector uses). A connector emits only the types that exist in the source model. Omit a row from your script’s assumptions unless that host actually publishes it.

Containment and grouping

These replace nested elements walks and most organisational Proxies. Grouping containers nest among themselves (a collection tree). That nesting is structural. It is not an object-to-object elements walk.

Connectivity

These are new as a queryable graph. Before 2026.9 there is no Proxy equivalent. CONNECTS_TO is directed in the store. Neighborhood queries used by the product treat it as a one-hop connection in either direction.

Display geometry

An object’s own geometry is a relation too, not a displayValue array on the object. The blob format behind these rows is on Geometry encoding in 2026.9. DISPLAY is what renders. SOLID and CENTERLINE are additional shapes for consumers that need the body or the axis. Do not draw every object-to-geometry relation, or the centerline appears through the middle of the duct.

Materials and appearance

Material and color are separate on purpose. An object can carry both. Material fills from specific to general: geometry HAS_MATERIAL, then OBJECT_HAS_MATERIAL, then the container’s NODE_HAS_MATERIAL. Color is presentational: OBJECT_HAS_COLOR overrides geometry HAS_COLOR, and NODE_HAS_COLOR is the ByLayer default.

Instancing

The Definition and Instance Proxies of 2026.8 and earlier become structural nodes plus relations.
DISPLAY_INSTANCE is the render root. PLACES is the same object-to-instance link without drawing. Do not treat a definition member as a render placement, or it will draw untransformed at the origin.

What a script should do instead of unpacking Proxies

1

Resolve the version

Use the same project, model, and version address you use today. The outcome is the snapshot you intend to read.
2

Identify objects by applicationId

Key source elements by applicationId, not by their position in a nested elements tree. The outcome is a stable object set across versions. If you are producing data rather than only reading it, this only holds if every placement’s applicationId is unique — a repeated id resolves to the same object, not a second occurrence.
3

Read the columnar property store

Take attributes from property paths on those objects. See Columnar property store. The outcome is values you can filter without walking nested Base fields.
4

Follow named relations

For membership, hosting, or connectivity, use relation names such as ON_LEVEL, SUBELEMENT, CONNECTS_TO, and IN_SYSTEM. The outcome is topology without unpacking a Proxy objects array. That join is already the relation.
This page does not document SQL, a local query API, or copy-paste SDK calls. Those surfaces are separate. Until they ship in these docs, use supported SDK accessors and the developer migration page for breakage and pinning.

FAQ

No. HOSTED_ON is placement on a host (a door on a wall). SUBELEMENT is ownership (a curtain wall owns its panels). A door is hosted on a wall; it is not a component of the wall.
The edge is absent. Scripts should treat a missing relation type as “not in this model,” not as a failed receive. Only hosts that have that concept in the source will emit it.
That walk is the tree of 2026.8 and earlier. On 2026.9 data, use IN_COLLECTION, IN_MODEL, ON_LEVEL, and SUBELEMENT instead of assuming a nested elements graph. See Object model in 2026.9.
No. Detaching and the reference object type belong to the object graph of 2026.8 and earlier; a bundle has no __closure to resolve them through. Publish the shared thing as its own object and relate the others to it, or, if what you are sharing is really a value rather than an object, write that value as a property on each object. See Object model in 2026.9.
No. It is the authored location curve. A Revit wall’s location line follows its Location Line setting and can be a core or finish face. A point-placed MEP fitting (elbow, tee, cross) has no location curve, so it emits one CENTERLINE segment per connector, ordered by connector.
No, and that is not the intent. Relations describe how finished objects relate: containment, hosting, connectivity, appearance, instancing. They do not describe how an object was made, and nothing in Speckle rebuilds geometry from a recipe. What you can carry: the exact body through SOLID in the host’s own format, feature parameters as properties, and ownership through SUBELEMENT. A dependency order can travel in your own edge file, which no Speckle consumer reads. Exchanging modelling history would need operation node kinds in the catalog and a modelling kernel on the receiving side. Neither exists today.
Yes, as a resolved structure. Parts are objects. A sub-assembly owns its parts through SUBELEMENT, or joins them through IN_ASSEMBLY when membership is the point. A part used many times is one definition placed by instances, each with its own transform, and a repeated sub-assembly is a nested definition. Part-to-part contact is CONNECTS_TO, and exact bodies ride SOLID. What does not travel is the constraint system: mates such as coincident or concentric, degrees of freedom, and the solver that positions parts from them. You publish the positions those constraints produced, not the constraints.
Yes. Store custom edges in your own parquet files, not in the relation files Speckle SDKs generate — rewriting those files mismatches on the next republish, and you own whatever you add. Do not mint unused numeric relation type ids from the Speckle catalog; Speckle reserves those numbers for future platform types. Which cases need a custom file, and which are really an existing relation or a property, is on Building integrations in 2026.9.
They are treated as the same object referenced twice, not as two occurrences. applicationId is not required on every object, but wherever it is relied on as identity — a DISPLAY_INSTANCE or DEFINES_INSTANCE placement, a Flatten().ToDictionary(o => o.applicationId) lookup, any join back to a source element — that identity has to be unique for the objects relying on it. A producer that reuses an id across two distinct placements will see the second one silently collapse onto the first: same node, same transform, no error raised.
Last modified on September 24, 2026