Configuration
Fresh uses a layered configuration system that allows you to customize settings at different levels of scope.
Configuration Layers
Settings are loaded from multiple layers, with higher layers overriding lower ones:
| Layer | Location | Scope | Use Case |
|---|---|---|---|
| System | Built-in defaults | Global | Factory defaults (read-only) |
| User | ~/.config/fresh/config.json | All projects | Personal preferences |
| Project | .fresh/config.json in project root | Single project | Project-specific settings |
| Session | .fresh/session.json (temporary) | Current session | Temporary overrides |
Path Notes:
- On Windows, User config is at
%APPDATA%\fresh\config.json - Project config is found by searching up from the current directory for
.fresh/config.json
How Layers Are Merged
When Fresh loads configuration, it merges all layers together. The merge behavior depends on the type of setting:
Simple Values (strings, numbers, booleans)
Higher layers completely override lower layers. If a setting is not specified in a higher layer, it falls through to the next lower layer.
System: theme = "default" ← Base default
User: theme = "dark" ← Overrides system
Project: (not set) ← Falls through
Session: theme = "light" ← Final value: "light"Nested Objects (editor, terminal, file_explorer)
Nested objects are deep-merged field by field. Each field follows the same "higher wins" rule independently.
Example: If User sets editor.tab_size = 4 and Project sets editor.line_wrap = true:
// User config
{ "editor": { "tab_size": 4, "line_numbers": true } }
// Project config
{ "editor": { "line_wrap": true } }
// Result: All fields merged
{ "editor": { "tab_size": 4, "line_numbers": true, "line_wrap": true } }Languages Map (deep merge)
The languages map uses deep merging with field-level override:
- Entries from all layers are combined (you can add new languages at any layer)
- For the same language key, individual fields are merged (not replaced entirely)
Example: Extending built-in Rust settings in your project:
// System (built-in): rust has extensions, grammar, etc.
// Project config - only need to specify what you're changing:
{
"languages": {
"rust": {
"tab_size": 2,
"format_on_save": true
}
}
}
// Result: Rust keeps all system defaults, with tab_size and format_on_save overriddenLSP Map (deep merge)
The lsp map uses deep merging with field-level override:
- Entries from all layers are combined
- For the same language key, individual fields are merged (not replaced entirely)
- Unspecified fields inherit from lower layers (you only need to specify what you're changing)
Example: To disable an LSP while preserving its default command:
{
"lsp": {
"rust": {
"enabled": false
}
}
}
// Result: rust-analyzer command preserved from defaults, just disabledLists (keybindings, on_save actions)
Lists are replaced entirely by higher layers - they are not merged or appended.
Example: If you define keybindings in your Project config, it completely replaces User keybindings (not extends them).
Using the Settings UI
The easiest way to configure Fresh is through the Settings UI:
- Open Settings: Press
Ctrl+,or use Command Palette → "Open Settings" - Browse Categories: Use arrow keys or click to navigate
- Change Values: Toggle booleans, adjust numbers, select from dropdowns
- Choose Target Layer: Click the layer button (e.g.,
[ User ]) to switch between User/Project/Session - Save: Press Enter on the Save button or use
Ctrl+S
Advanced: Edit Config File Directly
For complex configurations (like LSP args or custom keybindings), click the [ Edit ] button in the Settings footer to open the raw JSON config file for the selected layer.
Example Configurations
User config (~/.config/fresh/config.json) - your personal defaults:
{
"version": 1,
"theme": "dark",
"editor": {
"tab_size": 4,
"line_numbers": true
}
}Project config (.fresh/config.json) - project-specific overrides:
{
"version": 1,
"editor": {
"tab_size": 2
},
"languages": {
"javascript": {
"formatter": "prettier --write"
}
}
}Common Configuration Tasks
Add a Custom Language
To add syntax highlighting and LSP support for a new language:
{
"languages": {
"mylang": {
"extensions": ["ml", "myl"],
"grammar": "mylang",
"comment_prefix": "#",
"auto_indent": true
}
},
"lsp": {
"mylang": {
"command": "mylang-lsp",
"args": ["--stdio"],
"enabled": true
}
}
}Process Resource Limits
To prevent LSP servers from consuming too many resources, Fresh can limit their memory and CPU usage. This is configured in the process_limits section of your config.json file.
{
"lsp": {
"rust": {
"command": "rust-analyzer",
"enabled": true,
"process_limits": {
"max_memory_mb": 4096,
"max_cpu_percent": 200
}
}
}
}