Skip to main content
If you write scripts, notebooks, or small automations against Speckle object data, this page is the shape of that data. Speckle stores a version as two things working together: a columnar property store for querying and aggregation, and an explicit relational layer for how elements relate. Versions published before 2026.9 use a different shape. As the Data Schema describes, that object graph is a directed tree of Collections and DataObjects, with Proxies at the Root Collection for shared resources. Both shapes can exist in one project, so check which one a version uses before you read it. This page is the conceptual model. Dates, compatibility mode, Automate SDK bumps, and who must act are on Data model migration for developers. For a summary of everything that changed for developers in 2026.9, see What’s new for developers. There is no Proxy type anywhere in bundle data: not renamed, not kept around as a compatibility shim. No RenderMaterial, Level, Group, Definition, InstanceProxy, or InstanceDefinitionProxy object exists in the format. Everything a Proxy used to carry is either a row in the columnar property store or an edge in the relational layer. Detached references go with them. In the object graph, assigning one object to a detached property on several parents stored it once and left a {"speckle_type": "reference", "referencedId": ...} pointer in each, resolved through the parent’s __closure. A bundle has neither: there is no closure, and no reference object type. An object that several others need is an edge in the relational layer, and a value that several objects share is one row each in the property store.
Versions published before 2026.9 stay readable. To read bundle data, a script needs a 2026.9 SDK build; this page matters most if it walks the nested object graph or unpacks Proxies itself. See Data model migration for developers.

What’s different

Project → Model → Version remains the address of a published snapshot. That addressing system is unchanged. What lives at a version is what changed. What a version points at also changed. There is no root object to start from; see Where version metadata lives for what carries the version’s units, source application, and model-wide facts instead.

Columnar property store

In the object graph, a wall’s parameters live on the DataObject (and on nested geometry in displayValue). To total area or filter by type, a script walks the tree and reads nested fields. In bundle data, object identity stays stable (applicationId from the source application). Attributes are stored as rows in a columnar property store: each row is one object, one property path, and one value. That layout is what makes filter, group, and aggregate cheap on large models, instead of walking a reconstructed graph.
Treat property paths as the public names of attributes (for example a category or type name), not the JSON shape of a received Base object. Nested dictionaries belong to the object graph of versions published before 2026.9.
This page does not document a query API or SQL surface. Use supported SDK accessors for the data you already read. If a tool assumes the object-graph shape and breaks, follow Migration guidance.

Relational layer

Proxies solved overlapping membership without duplicating geometry: a wall could sit on a level, use a material, and belong to a group by appearing in each Proxy’s objects list. The collection tree was still the only hierarchy a traversal walked. Bundle data puts those links beside the property store as typed relations. Containment, connectivity, systems, and materials are richer than Proxies were: they include host-to-child containment, MEP and spatial connectivity, and system membership, not only shared resources at the root. The named relation types, and how they compare to Proxies, are on Relations. Speckle Intelligence uses both halves. It looks up properties on objects, and it follows relations for questions such as what connects to what and what contains what.

Publishing creates the version on the server

Before 2026.9, a publish is a client-side act in two steps. You assemble one root object, put every object under its elements (with Proxies beside them at the root), send that graph to get its id, then create a version that points at the id. The root object is both the data and the anchor, and the client decides the moment the version exists. A bundle has no root to assemble and no version to create. A bundle builder holds objects, grouping containers, and relations side by side, with no top. send3 / Send3 opens a model ingestion, which reserves a version id, uploads the bundle under that id, and completes the ingestion. The server creates the version at that point, in one step. Three habits change with this:
  • There is no elements to fill. Membership is a relation such as IN_COLLECTION or ON_LEVEL, set on the object, not a list on a parent.
  • Publish metadata is given up front. The source application goes to the ingestion when it opens. The current SDK uses SendOptions.Message as ingestion progress text and leaves Version.message null.
  • The version exists only after ingestion completes. A publish returns a reserved id. Wait for the version before you query, link, or receive it.
The full sequence, and where each piece of metadata now lives, is on Where version metadata lives. If you build a producer without a Speckle SDK, the file set, wire sequence, and bundle rules are on Build integrations on the bundle format.

What a script should assume

1

Keep using the version address

Resolve project, model, and version the same way as before. The snapshot you point at is still a version. The outcome is a published model you can read.
2

Identify objects, then properties

Key objects by source identity (applicationId). Read attributes from the columnar property store by property path. The outcome is values you can filter or aggregate without walking nested Base fields.
3

Follow typed relations for topology

Use named relations for level, material, containment, connectivity, and systems. The outcome is membership and connectivity without unpacking a Proxy’s objects array. See Relations.
Tooling that reads Speckle data more directly than the standard SDK or API surface breaks on bundle data until you update it. Compatibility mode keeps ACC sync and file uploads in the object graph only until 1 November 2026. See Migration guidance.
Connector-specific dumps and a SQL or local query API are not documented here. Use the Data Schema for the object graph of versions published before 2026.9, the .NET and Python migration pages for code, and the developer migration page for who is affected.

FAQ

Yes, for versions published in the tree-and-Proxy format before 2026.9. Use Data Schema overview, Concepts, and Proxy schema for that graph. Use this page for bundle data.
Yes, at least its SDK dependency. An SDK build from before 2026.9 gets a 404 on a version published by a 2026.9 connector. Move to a 2026.9 build, and to receive3 / Receive3 for the full bundle shape; Automate functions need only the SDK bump. See Who’s affected.
That reconstruction is the object graph of versions published before 2026.9. On bundle data, containment and shared resources live on the relational layer, and properties live in the columnar store. A missing nested elements tree or Proxy objects list is expected. Update the script to identify objects, read property paths, and follow named relations.
See Relations. That page maps Proxies to typed edges such as ON_LEVEL, SUBELEMENT, CONNECTS_TO, and IN_SYSTEM.
No. There is no RenderMaterial, Level, Group, Definition, InstanceProxy, or InstanceDefinitionProxy object in the format: not hidden, not deprecated-but-present. If your code checks for a Proxy type or a root-level *Proxies array on bundle data, it will find nothing, not an empty compatibility stand-in. See Relations for what carries that information now.
Last modified on October 19, 2026