# How bat's Configuration System Works: File-Based CLI Argument Management

> Understand bat's configuration system. Learn how bat manages CLI arguments using a simple file at ~/.config/bat/config, merging settings for customized output.

- Repository: [David Peter/bat](https://github.com/sharkdp/bat)
- Tags: internals
- Published: 2026-03-06

---

**bat's configuration system uses a plain-text file at `~/.config/bat/config` that stores command-line arguments, which are parsed at startup and merged with system-wide settings, environment variables, and explicit CLI flags.**

The `bat` syntax-highlighting pager implements a lightweight, file-based configuration system that mirrors its command-line interface. Unlike complex configuration formats, bat's configuration system treats each line in a config file as if it were a command-line argument, allowing users to persist any valid flag without learning new syntax.

## Core Components of bat's Configuration System

### The Configuration File Structure

The user configuration file lives at `~/.config/bat/config` on Linux and macOS, or `%APPDATA%\bat\config` on Windows. This plain-text file contains one command-line argument per line, with comments starting with `#`.

In [`src/bin/bat/config.rs`](https://github.com/sharkdp/bat/blob/main/src/bin/bat/config.rs), the `config_file()` function resolves this path using the `directories` crate, while `get_args_from_config_file()` handles reading and concatenating contents:

```rust
// From src/bin/bat/config.rs
pub fn config_file() -> Option<PathBuf> {
    env::var("BAT_CONFIG_PATH")
        .ok()
        .map(PathBuf::from)
        .or_else(|| PROJECT_DIRS.config_dir().join("config").into())
}

```

### System-Wide Configuration

Administrators can set defaults for all users via system-wide configuration files. The `system_config_file()` function locates these at `/etc/bat/config` on Unix systems or `C:\ProgramData\bat\config` on Windows.

The system configuration is read first, followed by the user configuration, allowing users to override system defaults while inheriting common settings.

### Environment Variable Overrides

bat's configuration system recognizes several environment variables that expand into command-line arguments:

- `BAT_OPTS`: Raw argument string appended directly to the command line
- `BAT_CONFIG_PATH`: Override the default config file location
- `BAT_THEME`, `BAT_THEME_DARK`, `BAT_THEME_LIGHT`: Theme selection
- `BAT_PAGER`, `BAT_PAGING`: Pager configuration
- `BAT_TABS`: Tab width
- `BAT_STYLE`: Display components (numbers, grid, header, etc.)

In [`src/bin/bat/config.rs`](https://github.com/sharkdp/bat/blob/main/src/bin/bat/config.rs), the `get_args_from_env_vars()` function maps these to `--flag=value` pairs, while `get_args_from_env_opts_var()` parses the free-form `BAT_OPTS` string using `shell_words::split`.

## How bat Reads and Merges Configuration

The configuration loading workflow follows a strict precedence order, implemented in [`src/bin/bat/config.rs`](https://github.com/sharkdp/bat/blob/main/src/bin/bat/config.rs):

1. **System config** is located via `system_config_file()` and read first
2. **User config** is located via `config_file()` and appended to the system config
3. **Environment variables** are converted to arguments via `get_args_from_env_vars()` and `get_args_from_env_opts_var()`
4. **CLI arguments** passed directly to the executable are appended last

The `get_args_from_str()` function parses configuration file contents using `shell_words::split`, which properly handles quoted strings and escape sequences. This produces a `Vec<OsString>` that mirrors actual command-line arguments.

Finally, this merged argument vector is passed to `clap` for parsing into the `Config` struct defined in [`src/config.rs`](https://github.com/sharkdp/bat/blob/main/src/config.rs):

```rust
// Simplified representation from src/config.rs
pub struct Config {
    pub language: Option<String>,
    pub theme: String,
    pub style_components: Vec<StyleComponent>,
    pub tab_width: usize,
    pub paging_mode: PagingMode,
    pub pager: Option<String>,
    // ... additional fields
}

```

## Practical Configuration Examples

### Generating a Starter Configuration

bat includes a utility to generate a template configuration file with all common options commented out:

```bash
bat --generate-config-file

```

This invokes the `generate_config_file()` function, which creates the parent directories if needed and writes a skeleton file to the default config location.

### Common User Configurations

A typical `~/.config/bat/config` might look like this:

```text

# Use the TwoDark theme for syntax highlighting

--theme="TwoDark"

# Display line numbers, Git changes, and file headers

--style="numbers,changes,header"

# Enable italic text if the terminal supports it

--italic-text=always

# Map Arduino .ino files to C++ syntax highlighting

--map-syntax "*.ino:C++"

# Set tab width to 4 spaces

--tabs=4

```

### Programmatic Access in Rust

Applications embedding bat can replicate the configuration loading process:

```rust
use bat::config::Config;
use std::ffi::OsString;

// Collect arguments from all configuration sources
let mut args: Vec<OsString> = Vec::new();

// Add config file arguments
if let Ok(config_args) = bat::bin::bat::config::get_args_from_config_file() {
    args.extend(config_args);
}

// Add environment variable arguments
if let Ok(env_opts) = bat::bin::bat::config::get_args_from_env_opts_var() {
    args.extend(env_opts);
}
args.extend(bat::bin::bat::config::get_args_from_env_vars());

// Parse into Config struct
let config = Config::parse_from(args);

```

## Summary

- bat's configuration system treats configuration files as persistent command-line arguments, with one flag per line in `~/.config/bat/config`.
- The system merges configuration in strict order: system-wide config → user config → environment variables → explicit CLI arguments.
- Key implementation files include [`src/bin/bat/config.rs`](https://github.com/sharkdp/bat/blob/main/src/bin/bat/config.rs) (loading and parsing) and [`src/config.rs`](https://github.com/sharkdp/bat/blob/main/src/config.rs) (the `Config` struct definition).
- Environment variables like `BAT_OPTS`, `BAT_THEME`, and `BAT_CONFIG_PATH` provide additional override mechanisms.
- Use `bat --generate-config-file` to create a template configuration with all available options.

## Frequently Asked Questions

### Where does bat store its configuration file?

By default, bat stores its configuration file at `~/.config/bat/config` on Linux and macOS, or `%APPDATA%\bat\config` on Windows. You can override this location by setting the `BAT_CONFIG_PATH` environment variable to a custom file path.

### What format does bat's configuration file use?

bat's configuration file uses a simple line-based format where each line represents a command-line argument. Comments start with `#`, and values containing spaces should be quoted. For example, `--theme="TwoDark"` or `--style=numbers,changes`. This format is parsed using `shell_words::split` in [`src/bin/bat/config.rs`](https://github.com/sharkdp/bat/blob/main/src/bin/bat/config.rs).

### Can I set system-wide defaults for all users?

Yes, administrators can create a system-wide configuration file at `/etc/bat/config` on Unix systems or `C:\ProgramData\bat\config` on Windows. The `system_config_file()` function in [`src/bin/bat/config.rs`](https://github.com/sharkdp/bat/blob/main/src/bin/bat/config.rs) locates this file, and its settings are loaded before user-specific configurations, allowing users to override system defaults while inheriting common settings.

### How do environment variables interact with the configuration file?

Environment variables are processed after configuration files but before explicit command-line arguments. Specific variables like `BAT_THEME`, `BAT_PAGER`, and `BAT_TABS` are mapped to their corresponding command-line flags, while `BAT_OPTS` accepts raw argument strings. This hierarchy ensures that CLI flags always take highest precedence, followed by environment variables, then user config, and finally system config.