This page provides an overview of how Windows Terminal defines, loads, and distributes settings throughout the application. It covers the top-level architecture: the CascadiaSettings object, the SettingsLoader pipeline, the layering model, and the extension/fragment system.
For implementation details, see the child pages:
The settings system is responsible for:
| Concern | Description |
|---|---|
| Schema definition | Defining all configurable properties for profiles, global settings, color schemes, themes, and actions |
| Persistence | Reading from and writing to settings.json on disk |
| Layering | Merging defaults, user settings, and fragments into a unified view |
| Extension | Allowing third-party apps to contribute profiles and color schemes via fragment JSON files |
| Dynamic profiles | Auto-discovering installed terminal environments |
| Validation | Detecting broken references, invalid media paths, and unknown color schemes |
The settings system lives in src/cascadia/TerminalSettingsModel/.
Settings System Component Diagram
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettings.h68-142
At runtime, settings files are resolved from the following paths:
| File | Purpose |
|---|---|
defaults.json | Inbox defaults, compiled into the binary as a resource |
%LOCALAPPDATA%\Packages\...\LocalState\settings.json | User settings (packaged) |
%LOCALAPPDATA%\Microsoft\Windows Terminal\settings.json | User settings (unpackaged) |
%LOCALAPPDATA%\Microsoft\Windows Terminal\Fragments\<app>\*.json | Per-user fragment files |
%PROGRAMDATA%\Microsoft\Windows Terminal\Fragments\<app>\*.json | Machine-wide fragment files |
CascadiaSettings exposes SettingsPath() and DefaultSettingsPath() as static methods to get these paths at runtime. See src/cascadia/TerminalSettingsModel/CascadiaSettings.h150-153
The SettingsLoader class drives the entire load sequence. CascadiaSettings::LoadAll() is the primary entry point; SettingsLoader::Default() is a simplified version used in unit tests.
SettingsLoader Pipeline
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp116-123 src/cascadia/TerminalSettingsModel/CascadiaSettings.h82-98
Settings are inherited from parent objects using a directed acyclic graph. Each Profile or GlobalAppSettings can have multiple parents, resolved in priority order. This is what lets a user override only specific fields without repeating defaults everywhere.
Profile Inheritance Hierarchy
The OriginTag enum encodes where a setting value came from:
| OriginTag | Source |
|---|---|
InBox | Parsed from defaults.json |
User | Parsed from user settings.json |
Fragment | Parsed from a fragment file or app extension |
ProfilesDefaults | The profiles.defaults object in settings.json |
Layering is finalized in SettingsLoader::FinalizeLayering() which calls _FinalizeInheritance() on each object. See src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp464-503
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp310-503
ParsedSettings is an intermediate holding structure used by SettingsLoader during the parsing phase. It is not exposed publicly.
ParsedSettings
├── globals: GlobalAppSettings
├── baseLayerProfile: Profile
├── profiles: vector<Profile>
├── profilesByGuid: unordered_map<guid, Profile>
├── colorSchemes: unordered_map<hstring, ColorScheme>
└── colorSchemeRemappings: unordered_map<hstring, hstring>
Two instances are maintained simultaneously: inboxSettings and userSettings. After MergeInboxIntoUserSettings(), inbox profiles are wired as parents of user profiles and userSettings becomes the authoritative state.
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettings.h68-80
Third-party applications and scripts can contribute profiles and color schemes by placing JSON files in known directories. The SettingsLoader::FindFragmentsAndMergeIntoUserSettings() method scans these locations.
Fragment Discovery and Merge Flow
Fragment profiles may use either a guid (to add a new profile) or an updates key (to modify an existing profile by GUID). Fragments may not bind keybindings directly. The _ignoredNamespaces set (populated from user settings and Group Policy DisabledProfileSources) gates which fragment sources are applied.
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp329-449 src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp881-1010
Before the inbox-to-user merge step, SettingsLoader::GenerateProfiles() calls each registered IDynamicProfileGenerator to discover installed terminals. Generated profiles are added to inboxSettings and thus appear as parents of user profiles.
Registered generators (as of current code):
| Generator | What it discovers |
|---|---|
PowershellCoreProfileGenerator | Store, Scoop, .NET tool, and traditional PS installs |
WslDistroGenerator | WSL distributions via the Lxss registry |
AzureCloudShellGenerator | Azure Cloud Shell connection |
VisualStudioGenerator | Developer Command Prompt and PowerShell for VS |
SshHostGenerator | SSH hosts (feature-flagged) |
See src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp208-230 and Dynamic Profile Generators for details.
After construction, CascadiaSettings::_validateSettings() runs a series of checks. Any issues that are non-fatal are collected into the _warnings list. Fatal errors set _loadError.
| Validation method | What it checks |
|---|---|
_validateAllSchemesExist() | All colorScheme references in profiles point to real schemes |
_validateMediaResources() | Icons and background images can be resolved to real files or URIs |
_validateKeybindings() | Keybinding definitions are well-formed |
_validateColorSchemesInCommands() | setColorScheme commands reference valid schemes |
_validateThemeExists() | The active theme name exists in the theme map |
_validateProfileEnvironmentVariables() | No case-insensitive-duplicate env var keys in a profile |
_validateRegexes() | MatchProfilesEntry regexes in the new tab menu compile successfully |
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp438-447 src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp459-713
CascadiaSettings is a WinRT runtime class exposed via IDL. Its key surface:
| Member | Purpose |
|---|---|
LoadAll() | Full load from disk, generators, and fragments |
LoadDefaults() | Load only from defaults.json (used in settings editor) |
WriteSettingsToDisk() | Serialize and save settings.json |
Copy() | Deep-clone the entire settings graph (used by settings editor to edit a copy) |
GlobalSettings | Returns the GlobalAppSettings object |
AllProfiles / ActiveProfiles | All profiles / only non-hidden, non-orphaned ones |
ProfileDefaults | The profiles.defaults base layer profile |
FindProfile(guid) | Lookup a profile by GUID |
GetProfileForArgs(NewTerminalArgs) | Resolve a profile from command-line args |
DuplicateProfile(source) | Create a new profile copying the effective settings of another |
Extensions | Lazily-loaded list of ExtensionPackage objects (for the settings UI) |
Warnings | Collection of SettingsLoadWarnings gathered during load |
Sources: src/cascadia/TerminalSettingsModel/CascadiaSettings.idl17-70 src/cascadia/TerminalSettingsModel/CascadiaSettings.h144-250
Settings are consumed across multiple subsystems:
AppLogic holds the live CascadiaSettings instance and reloads it when settings.json changes on disk.TerminalPage calls SetSettings() to propagate updated settings to all open tabs and panes.Copy() of the settings and calls WriteSettingsToDisk() when the user saves.ControlCore receives an ICoreSettings and ICoreAppearance projection of the relevant profile, not the full CascadiaSettings.For the UI layer details, see Terminal Page and Action Dispatch. For the settings editor UI itself, see Settings Editor UI.
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.