This page covers how Windows Terminal defines, loads, serializes, and layers all settings at runtime. It describes the CascadiaSettings class, the SettingsLoader pipeline, profile and global settings classes, the macro-based property system in MTSMSettings.h, the fragment/extension mechanism, and the interface hierarchy exposed to the terminal control.
For the Settings Editor UI that reads from these model objects, see page 5.2 For dynamic profile generators that feed profiles into the loader, see page 5.3
All settings live in src/cascadia/TerminalSettingsModel/. The central type is CascadiaSettings, which aggregates a GlobalAppSettings object, a base-layer profile (profiles.defaults), a list of all profiles, and any load errors or warnings. Settings from multiple sources — the embedded defaults.json, the user's settings.json, dynamic profile generators, and JSON fragment files from third-party extensions — are merged together by a helper class called SettingsLoader before CascadiaSettings is constructed.
| Type | File | Role |
|---|---|---|
CascadiaSettings | CascadiaSettings.h, CascadiaSettings.cpp | Top-level settings container; public WinRT surface |
SettingsLoader | CascadiaSettings.h, CascadiaSettingsSerialization.cpp | Orchestrates load, merge, and layering pipeline |
ParsedSettings | CascadiaSettings.h | Plain struct holding one parsed JSON document's worth of settings objects |
GlobalAppSettings | GlobalAppSettings.idl, GlobalAppSettings.h | App-wide settings (window, tabs, keybindings, themes, color schemes) |
Profile | Profile.h, Profile.cpp | Per-profile settings with inheritance |
AppearanceConfig | AppearanceConfig.h | Appearance sub-object for a profile (focused or unfocused) |
FontConfig | FontConfig.h | Font sub-object for a profile |
FragmentSettings | CascadiaSettings.h | Represents one .json fragment file from an extension |
ExtensionPackage | CascadiaSettings.h | Groups all FragmentSettings from one extension source |
ParsedSettings structure (src/cascadia/TerminalSettingsModel/CascadiaSettings.h68-80):
globals → com_ptr<GlobalAppSettings>
baseLayerProfile → com_ptr<Profile> (profiles.defaults)
profiles → vector<com_ptr<Profile>>
profilesByGuid → unordered_map<guid, com_ptr<Profile>>
colorSchemes → unordered_map<hstring, com_ptr<ColorScheme>>
colorSchemeRemappings→ unordered_map<hstring, hstring>
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettings.h68-80 src/cascadia/TerminalSettingsModel/CascadiaSettings.h144-250
CascadiaSettings::LoadAll() is the production entry point. SettingsLoader::Default() is the test/unit-test entry point that skips file I/O and dynamic profile generation.
Settings loading pipeline (production)
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp116-123 src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp208-230 src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp314-450 src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp464-503
SettingsLoader::Default() (unit tests) skips generators, fragments, and DisableDeletedProfiles:
SettingsLoader{ userJSON, inboxJSON }
→ MergeInboxIntoUserSettings()
→ FinalizeLayering()
→ FixupUserSettings()
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp116-123
Each Profile implements IInheritable<Profile>. Settings are resolved by walking a parent chain: the first parent that has a value "wins". The inheritance is a directed acyclic graph (DAG) — a profile can have multiple parents.
Typical inheritance chain for a user-defined profile
The key methods that build this graph:
| Method | Where called | What it does |
|---|---|---|
_addUserProfileParent(inboxProfile) | MergeInboxIntoUserSettings() | Finds/creates matching user profile and makes inbox profile a parent |
AddLeastImportantParent(parent) | FinalizeLayering() | Appends parent at lowest priority |
AddMostImportantParent(parent) | FinalizeLayering() | Prepends parent at highest priority |
_FinalizeInheritance() | FinalizeLayering() | Propagates parents into sub-objects (AppearanceConfig, FontConfig) |
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp310-320 src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp464-503 src/cascadia/TerminalSettingsModel/Profile.cpp239-267
MTSMSettings.hAll settings properties across GlobalAppSettings, Profile, AppearanceConfig, and FontConfig are declared using X-macro lists in src/cascadia/TerminalSettingsModel/MTSMSettings.h The macro format is:
X(type, name, jsonKey, defaultArgs...)
Four lists exist:
| Macro | Applied to | Example entry |
|---|---|---|
MTSM_GLOBAL_SETTINGS | GlobalAppSettings | X(bool, CopyOnSelect, "copyOnSelect", false) |
MTSM_PROFILE_SETTINGS | Profile | X(int32_t, HistorySize, "historySize", DEFAULT_HISTORY_SIZE) |
MTSM_FONT_SETTINGS | FontConfig | X(hstring, FontFace, "face", DEFAULT_FONT_FACE) |
MTSM_APPEARANCE_SETTINGS | AppearanceConfig | X(bool, UseAcrylic, "useAcrylic", false) |
These macro lists are instantiated in multiple contexts:
In Profile.h — declares inheritable properties:
In Profile.cpp LayerJson() — reads each property from JSON:
In Profile.cpp ToJson() — writes each property to JSON:
In CascadiaSettings.cpp DuplicateProfile() — copies each property:
Adding a new setting to any of these classes only requires adding one line to the appropriate macro list in MTSMSettings.h, plus corresponding entries in the IDL file and ControlProperties.h if the setting needs to be visible to the terminal control.
Sources: src/cascadia/TerminalSettingsModel/MTSMSettings.h21-175 src/cascadia/TerminalSettingsModel/Profile.h139-142 src/cascadia/TerminalSettingsModel/Profile.cpp204-209 src/cascadia/TerminalSettingsModel/Profile.cpp348-353 src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp316-320
Settings flow from the settings model down to the terminal core through a chain of WinRT interfaces. ControlProperties.h mirrors the IDL definitions with C++ macros for use in non-WinRT contexts (e.g. MockTermSettings in unit tests).
Interface hierarchy from core to control
Corresponding macro lists in ControlProperties.h
| Macro | IDL interface |
|---|---|
CORE_APPEARANCE_SETTINGS | ICoreAppearance / ICoreScheme |
CONTROL_APPEARANCE_SETTINGS | IControlAppearance |
CORE_SETTINGS | ICoreSettings |
CONTROL_SETTINGS | IControlSettings |
Sources: src/cascadia/TerminalCore/ICoreSettings.idl84-138 src/cascadia/TerminalControl/IControlSettings.idl37-82 src/cascadia/inc/ControlProperties.h1-91
Third-party apps and packages can inject profiles and color schemes into Windows Terminal via fragment JSON files. FindFragmentsAndMergeIntoUserSettings() scans three locations:
| Source | Path | Scope |
|---|---|---|
| User AppData | %LOCALAPPDATA%\Microsoft\Windows Terminal\Fragments\<source>\*.json | FragmentScope::User |
| Machine ProgramData | %PROGRAMDATA%\Microsoft\Windows Terminal\Fragments\<source>\*.json | FragmentScope::Machine |
| App Extensions | AppExtensionCatalog::Open("com.microsoft.windows.terminal.settings") → Fragments\*.json | FragmentScope::User |
Fragment object model
Each fragment JSON can:
profiles.list)updates key referencing a GUID)schemes)The _ignoredNamespaces set in SettingsLoader filters out sources listed in disabledProfileSources (from settings.json) or from the registry key Software\Policies\Microsoft\Windows Terminal\DisabledProfileSources.
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp329-450 src/cascadia/TerminalSettingsModel/CascadiaSettings.h46-66 src/cascadia/TerminalSettingsModel/CascadiaSettings.h252-312 src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp145-187
After layering, CascadiaSettings::_validateSettings() runs several checks and populates _warnings:
| Validator | Warning added |
|---|---|
_validateAllSchemesExist() | UnknownColorScheme |
_validateMediaResources() | InvalidMediaResource |
_validateKeybindings() | (keybinding conflicts) |
_validateColorSchemesInCommands() | (missing scheme in command) |
_validateThemeExists() | (missing theme name) |
_validateProfileEnvironmentVariables() | InvalidProfileEnvironmentVariables |
_validateRegexes() | InvalidRegex |
Warnings are non-fatal; errors (e.g. JSON parse failures) are stored in _loadError and _deserializationErrorMessage and surfaced as SettingsLoadErrors.
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp438-447 src/cascadia/TerminalSettingsModel/CascadiaSettings.h183-186
FixupUserSettings() applies schema migrations so settings written for older releases continue to work correctly. Examples:
| Version | Migration |
|---|---|
| 1.x | Commandline paths for cmd.exe and powershell.exe normalized to full %SystemRoot% paths |
| 1.19 | Global compatibility.reloadEnvironmentVariables moved to per-profile setting |
| 1.23 | Global experimental.input.forceVT moved to per-profile setting |
| 1.24 | Ensures newTabMenu always exists with a RemainingProfilesEntry |
When FixupUserSettings() returns true, the caller rewrites settings.json to disk to persist the migration.
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp608-703
Deserialization — Profile::FromJson() creates a new Profile, then calls LayerJson(), which calls JsonUtils::GetValueForKey() for each property in the MTSM_PROFILE_SETTINGS macro list. Sub-objects (AppearanceConfig, FontConfig) have their own LayerJson() methods called from Profile::LayerJson().
Serialization — Profile::ToJson() builds a Json::Value object by calling JsonUtils::SetValueForKey() for each macro entry. Only values that are set on this specific profile (i.e., stored in _name optional fields) are written; inherited values are intentionally omitted.
CascadiaSettings::WriteSettingsToDisk() serializes the full settings to a styled JSON string (4-space indent, YAML-compatible) using Json::StreamWriterBuilder configured in SettingsLoader::_getJsonStyledWriter().
Sources: src/cascadia/TerminalSettingsModel/Profile.cpp151-365 src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp191-204
When a new terminal pane is opened, the app creates a TerminalSettings object (in TerminalSettingsAppAdapterLib) that implements IControlSettings. It pulls values from a Profile and the GlobalAppSettings and presents them through the IControlSettings / ICoreSettings interface chain to TermControl and ControlCore.
Data flow: settings model → terminal control
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettings.h144-250 src/cascadia/inc/ControlProperties.h1-91 src/cascadia/TerminalControl/IControlSettings.idl37-82 src/cascadia/TerminalCore/ICoreSettings.idl84-138
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.