5.10.0 Change Notes
@itwin/core-backend
ECSQL CROSS JOIN now supports optional ON clause
CROSS JOIN in ECSQL now accepts an optional ON condition, matching standard SQL and SQLite behavior. Previously, CROSS JOIN only produced an unfiltered Cartesian product between two classes.
The key benefit of using CROSS JOIN with an ON clause — rather than INNER JOIN — is optimizer control: SQLite's special CROSS JOIN handling prevents the query planner from reordering the joined tables, giving applications explicit control over the join order and query execution plan.
Example — filter the Cartesian product while locking join order:
This is equivalent in result to an INNER JOIN, but the optimizer is not permitted to swap the table order, which can be important for performance-sensitive queries.
Schema changesets can be reversed
This makes it possible to walk a changeset timeline backwards through interleaved schema and data changesets. After reversing a schema changeset, the EC metadata (class definitions, property mappings, schema version) reflects the state prior to that changeset.
As a result, CheckpointManager.downloadCheckpoint now succeeds when the target changeset is older than the checkpoint and the range spans one or more schema changesets. Previously this would fail because schema changesets could not be reversed.
ChangesetReader: enableStrictMode and disableStrictMode
ChangesetReader gains ChangesetReader.enableStrictMode and ChangesetReader.disableStrictMode to toggle strict column-count checking. In strict mode a mismatch between a change record and the live table column count throws immediately; in lenient mode (the default) the minimum column count is used instead. See Strict mode for details.
ChangesetReader: spillThresholdInBytes controls disk spill for bounded memory use
ChangesetReader.openGroup, ChangesetReader.openTxn, ChangesetReader.openLocalChanges, and ChangesetReader.openInMemoryChanges now accept spillThresholdInBytes to bound peak memory by spilling change data to a temporary file on disk when the threshold is exceeded (default 50 MiB). See spillThresholdInBytes for details.
ChangesetReader: close and Symbol.dispose can now throw
ChangesetReader.close (and [Symbol.dispose]()) can now propagate errors from the native layer; previously they were silently swallowed. Code using manual [Symbol.dispose]() calls in a finally block may need updating — see Disposal for the safe patterns. Code using using is unaffected.
@itwin/core-quantity
Generated unit identifiers and sync built-in conversion helpers
@itwin/core-quantity now exposes beta Units, Phenomena, UnitSystems, and UnitConversions helpers for the built-in canonical unit set shipped with the package. This gives callers discoverable package-owned identifiers instead of magic strings, grouped unit browsing by phenomenon, and a synchronous built-in conversion path for canonical bundled units.
Units includes bundled BIS InvertedUnit identifiers inside their natural phenomenon buckets, removing magic-string cases for ratio-style units such as Units.HORIZONTAL_PER_VERTICAL.
The package also now exposes beta getDefaultPersistenceUnit for the package's default built-in persistence unit of a supported bundled phenomenon. Phenomena.LENGTH_RATIO is intentionally excluded from that helper because the bundled built-in unit set does not currently provide an agreed default for that phenomenon.
Additionally, Quantity.convertTo now throws QuantityError with QuantityStatus.InvalidUnitConversion when given UnitConversionProps marked with error: true, matching the newer UnitConversions throwing helpers. Callers that previously relied on convertTo(...) silently applying identity math for invalid conversions should update to handle this error explicitly.
Electron 42 support
In addition to already supported Electron versions, iTwin.js now supports Electron 42.
Last Updated: 03 June, 2026