Every non-trivial iTwin.js application needs two things at run-time: configuration (which tools are available, what units to use, which data sources are active) and resources (binary assets like fonts, textures, and templates). iTwin.js provides two complementary systems to address these needs:
- Settings — a priority-ordered stack of key-value configuration pairs. Configuration flows from cloud-hosted settings containers into the active Settings runtime, where values can be read by name.
- Workspace resources — versioned binary assets stored in WorkspaceDb containers. Settings tell the application which
WorkspaceDbs to load; the application then retrieves resources from them.
These two systems are deliberately separate. Settings containers are discoverable without opening an iModel. WorkspaceDb containers are referenced by settings. This separation eliminates the circular dependency that would arise if settings had to be loaded from a WorkspaceDb just to discover which WorkspaceDb to open.
At runtime, settings and resources are accessed through one of three workspace scopes:
| Workspace | Scope | Access |
|---|---|---|
| IModelHost.appWorkspace | Application-wide defaults and configuration | Available immediately after IModelHost.startup |
| IModelHost.getITwinWorkspace | iTwin-scoped settings shared across all iModels in an iTwin | Requires an iTwinId; no iModel needed |
| IModelDb.workspace | iModel-specific overrides; falls back to appWorkspace for unresolved settings. Does not automatically include iTwin-scoped settings |
Available when an iModel is open |
appWorkspace and IModelDb.workspace share the same priority stack, so iModel-level settings automatically override application defaults. getITwinWorkspace is independent — its settings are only available to an iModel if explicitly referenced (see Referencing iTwin settings from an iModel). See Choosing the right workspace for guidance on when to use each scope.
Both container types are built on CloudSqlite with WorkspaceDb as the underlying database, but they serve different roles and are discovered differently.
graph LR
subgraph CloudSqlite["CloudSqlite"]
direction TB
note["Versioned · Immutable once published<br/>Semver-based · Container-scoped"]
end
subgraph SettingsContainer["Settings container (containerType: "settings")"]
SDB["<b>Settings</b><br/>Key-value config<br/>JSON dictionaries<br/>Priority-based merge"]
end
subgraph WorkspaceContainer["Workspace container (containerType: "workspace")"]
WDB["<b>Resources</b><br/>Named resources<br/>Strings, blobs, files<br/>On-demand lookup"]
end
CloudSqlite --- SettingsContainer
CloudSqlite --- WorkspaceContainer
SDB -->|"settings point to"| WDB
| Settings container | Workspace container | |
|---|---|---|
| Purpose | Application configuration | Data resources |
| Content | JSON key-value dictionaries | Strings, blobs, embedded files |
| Container type | "settings" |
"workspace" |
| Discovery | Automatic via IModelHost.getITwinWorkspace — no iModel needed | Referenced from settings values |
| Resolution order | Loaded first | Loaded second, via settings pointers |
| Write API | WorkspaceEditor with containerType: "settings" |
WorkspaceEditor |
| Versioning | Semver — immutable once published | Semver — immutable once published |
At runtime the flow always starts from settings:
- Discover and load — call IModelHost.getITwinWorkspace with an iTwinId. This automatically discovers settings containers for the iTwin, loads their dictionaries into the Settings priority stack, and returns a Workspace ready to use. No iModel is required.
- Resolve resources — read settings values that point to WorkspaceDb containers, then open those containers to access resources.
For advanced scenarios (admin tooling, custom discovery logic), WorkspaceEditor.queryContainers provides lower-level access to enumerate containers by iTwinId and
containerType.
Settings from multiple sources are merged using a priority stack. A higher-priority dictionary overrides a lower-priority one for any given setting name.
graph TD
subgraph AppWorkspace["IModelHost.appWorkspace"]
D["defaults (100)"]
A["application (200)"]
O["organization/iTwin (400)"]
end
subgraph IModelWorkspace["IModelDb.workspace"]
B["branch (500)"]
M["iModel (600)"]
end
D -->|"overridden by"| A
A -->|"overridden by"| O
O -->|"overridden by"| B
B -->|"overridden by"| M
style M fill:#d4edda,stroke:#28a745
style D fill:#f8f9fa,stroke:#6c757d
In practice:
- Organization-wide defaults are stored in a settings container and loaded at SettingsPriority.iTwin (400).
- iModel-specific overrides are loaded at SettingsPriority.iModel (600) — iModel wins over iTwin.
- Application defaults are loaded at SettingsPriority.application (200) — overrideable by any cloud-backed settings.
Note: The diagram above simplifies organization and iTwin into one level. The full priority stack includes a separate SettingsPriority.organization (300) level — see Settings priorities for details.
IModelHost.appWorkspace holds dictionaries at application priority or lower. IModelDb.workspace holds higher-priority dictionaries and falls back to appWorkspace when a setting is not found.
IModelHost.getITwinWorkspace handles settings container discovery automatically — it queries for containers tagged with containerType: "settings", loads their dictionaries, and returns a ready-to-use Workspace. Most application code does not need to interact with the discovery layer directly.
WorkspaceDb containers (containerType: "workspace") are discovered indirectly — by reading settings values that point to them. See Workspace resources for details.
For admin tooling or custom workflows, WorkspaceEditor.queryContainers provides direct access to enumerate containers by iTwinId and
containerType. See Settings containers for examples.
- This overview — understand the two systems and three workspace scopes.
- Settings — how to define settings schemas, load dictionaries, read values, and create/manage settings containers in the cloud.
- Workspace resources — how to create, version, and access binary resources stored in WorkspaceDb containers.