Lazygit Configuration File Structure: How User Config is Loaded and Parsed
Lazygit stores user settings in a single YAML file named config.yml, locates it via XDG Base Directory specifications or the LG_CONFIG_FILE environment variable, and loads it through a validation pipeline that migrates legacy keys and merges multiple files when specified.
The lazygit terminal UI (jesseduffield/lazygit) derives its runtime behavior from a hierarchical configuration defined in Go structs and serialized as YAML. Understanding the lazygit configuration file structure helps you customize keybindings, UI themes, and git workflows effectively.
Config File Location and Discovery
Lazygit resolves the configuration path through a deterministic search hierarchy implemented in pkg/config/app_config.go.
Default XDG Paths and Environment Overrides
The findConfigFile function checks locations in the following order:
- Direct override: If the
CONFIG_DIRenvironment variable is set, lazygit uses that path directly. - Historic path: Checks for
jesseduffield/lazygitunderXDG_CONFIG_HOMEor system directories (legacy support). - Current default: Looks for the
lazygitdirectory underXDG_CONFIG_HOME. - Fallback: Uses
$XDG_CONFIG_HOME/lazygit/config.ymlif no other location exists.
The filename constant is defined as:
var ConfigFilename = "config.yml"
Source: pkg/config/app_config.go lines 108–109
The LG_CONFIG_FILE Environment Variable
When LG_CONFIG_FILE contains a comma-separated list of file paths, lazygit bypasses the standard discovery logic and loads those specific files instead. This enables configuration splitting across multiple YAML documents.
export LG_CONFIG_FILE=$HOME/.config/lazygit/work.yml,$HOME/.config/lazygit/personal.yml
lazygit
YAML Structure and Schema
The configuration schema mirrors the UserConfig struct defined in pkg/config/user_config.go. Each top-level YAML key maps to a nested Go struct that controls specific subsystems.
Top-Level UserConfig Sections
| YAML Key | Go Struct | Purpose |
|---|---|---|
gui |
GuiConfig |
UI appearance, colors, panel layouts, and scroll behavior |
git |
GitConfig |
Paging commands, commit conventions, branch handling, and merge preferences |
update |
UpdateConfig |
Automatic update check frequency and policy |
refresher |
RefresherConfig |
Background repository refresh intervals and fetch automation |
keybinding |
KeybindingConfig |
Custom key mappings overriding defaults |
os |
OSConfig |
External editor commands, file openers, and clipboard integrations |
customCommands |
[]CustomCommand |
User-defined menu items accessible within the TUI |
services |
map[string]string |
URL templates for generating pull requests and branch links |
Source: pkg/config/user_config.go lines 9–41
Each sub-struct uses YAML tags that match the configuration keys exactly, ensuring 1:1 parity between the YAML document and the internal representation.
Config Loading Pipeline
When the application initializes, NewAppConfig orchestrates the configuration bootstrap in pkg/config/app_config.go.
Initialization with NewAppConfig
The constructor builds a slice of ConfigFile objects representing the files to load:
path := filepath.Join(configDir, ConfigFilename)
configFile := &ConfigFile{
Path: path,
Policy: ConfigFilePolicyCreateIfMissing,
}
If LG_CONFIG_FILE is unset, lazygit falls back to the default location and sets a policy to create the file if absent.
Step-by-Step Loading Process
The loadUserConfigWithDefaults function delegates to loadUserConfig, which executes the following pipeline:
- Stat each file – Records existence and modification timestamps via
os.Stat. - Create missing files – Generates an empty
config.ymlif the policy isCreateIfMissingand no file exists. - Read contents – Loads raw bytes using
os.ReadFile. - Migrate schemas – Runs
migrateUserConfigto transform deprecated keys (e.g., renaminggui.skipUnstageLineWarningtogui.skipDiscardChangeWarning, or convertinggit.pagingscalars togit.pagersarrays). - Unmarshal YAML – Parses into a base
UserConfiginitialized withGetDefaultConfigvalues. - Append custom commands – Merges
customCommandsfrom earlier files in the load order, preserving sequence. - Validate – Executes
base.Validate()to enforce constraints and return actionable errors.
The final populated struct is stored in AppConfig.userConfig and accessed via GetUserConfig().
Source: pkg/config/app_config.go lines 42–55
Runtime Reloading and File Watching
Lazygit monitors configuration timestamps to support hot-reloading without process restart. The ReloadChangedUserConfigFiles method iterates through known config paths, compares current ModTime values against cached records, and re-executes the loading pipeline when discrepancies are detected.
if err := appConfig.ReloadChangedUserConfigFiles(); err != nil {
log.Println("Config reload failed:", err)
}
Source: pkg/config/app_config.go lines 58–71
Configuration Migration
Lazygit maintains backward compatibility through automatic schema migration. When migrateUserConfig detects legacy keys, it rewrites the file on disk (if the UI is initialized) and prints a human-readable summary of changes. This ensures that upgrading lazygit never breaks existing user settings, even when the internal UserConfig struct evolves.
Source: pkg/config/app_config.go lines 14–33
Accessing Configuration Values
After initialization, application code retrieves settings through the getter methods:
appConfig, err := config.NewAppConfig("lazygit", version, commit, date, buildSource, debuggingFlag, tempDir)
if err != nil {
log.Fatal(err)
}
// Access specific settings
theme := appConfig.GetUserConfig().Gui.Theme
fmt.Println("Active border color:", theme.ActiveBorderColor)
Summary
- Location: Lazygit searches
XDG_CONFIG_HOME/lazygit/config.ymlby default, respecting theLG_CONFIG_FILEenvironment variable for custom paths or multiple files. - Structure: The YAML hierarchy maps directly to the
UserConfigstruct inpkg/config/user_config.go, with sections forgui,git,keybinding,customCommands, and more. - Loading:
NewAppConfigtriggersloadUserConfig, which stats files, creates missing defaults, migrates legacy keys, unmarshals YAML, and validates the final struct. - Reloading:
ReloadChangedUserConfigFileschecks modification times and re-parses changed files during runtime. - Migration: Automatic schema updates handle deprecated keys like
gui.skipUnstageLineWarning→gui.skipDiscardChangeWarningwithout manual intervention.
Frequently Asked Questions
Where is the lazygit config file stored on my system?
By default, lazygit places the file at $XDG_CONFIG_HOME/lazygit/config.yml (typically ~/.config/lazygit/config.yml on Linux). On macOS, this resolves to ~/Library/Application Support/lazygit/config.yml, and on Windows to %LOCALAPPDATA%\lazygit\config.yml. You can override this location by setting the LG_CONFIG_FILE environment variable to a specific path.
Can I split my lazygit configuration across multiple files?
Yes. Set LG_CONFIG_FILE to a comma-separated list of absolute paths. Lazygit loads these files in order, with later files appending customCommands and overriding scalar values. This is useful for maintaining separate work and personal profiles.
What happens to my old config settings when lazygit updates?
Lazygit automatically migrates deprecated configuration keys when loading the file. The migrateUserConfig function rewrites the YAML on disk to match the current schema, converting legacy structures like scalar git.paging values into the newer git.pagers array format. You receive a notification summarizing any automatic changes.
How do I reload the configuration without restarting lazygit?
Lazygit watches config file modification times automatically, but you can trigger an immediate reload programmatically using appConfig.ReloadChangedUserConfigFiles(). In the TUI, the "Reload config" command forces a fresh read of all configured files, applying new keybindings or theme changes instantly.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →