Starship is a minimal, blazing-fast, infinitely customizable cross-shell prompt written in Rust (2024 edition, MSRV 1.90). It detects your development environment automatically and renders a rich, informative prompt across every major shell. Version 1.24.2, ISC license.
This guide covers architecture, configuration internals, build processes, performance tuning, security considerations, and developer workflows — everything needed to deploy, operate, maintain, or contribute to Starship at the source level.
1. Architecture Overview
1.1 High-Level Execution Model
Starship operates as a stateless CLI binary invoked by shell hooks before each prompt render. There is no daemon, no background process, and no persistent state between invocations. The full lifecycle for every prompt:
- The user runs
eval "$(starship init <shell>)"once per session, which registers shell-specific hooks (precmd, preexec, or equivalent) - Before each prompt display, the shell hook calls
starship promptwith properties including exit status, command duration, number of jobs, terminal width, and keymap - Starship reads
~/.config/starship.toml(or$STARSHIP_CONFIG), builds aContextstruct - The
Contextscans the current directory, discovers git repositories, detects language/tool presence via file extensions, filenames, and folder names - Each module in
PROMPT_ORDERis invoked — modules returnNoneif their detection criteria are not met, orSome(Module)with rendered segments - Modules execute in parallel via rayon when safe; shared state (e.g., between
git_statusandgit_metrics) is coordinated throughparking_lotmutexes StringFormatterprocesses format strings through a PEG parser- The final prompt string is assembled and printed to stdout
┌──────────────────────────────────────────────────────────┐
│ Shell (bash/zsh/fish/pwsh/elvish/nu/cmd/tcsh/xonsh) │
│ eval "$(starship init <shell>)" │
│ ↓ precmd hook │
│ starship prompt --status=$? --cmd-duration=... │
└──────────────┬───────────────────────────────────────────┘
│
┌──────────────▼───────────────────────────────────────────┐
│ main.rs → CLI dispatch (clap derive) │
│ ↓ │
│ context.rs → Context { shell, env, dir, git_repo } │
│ ↓ │
│ config.rs → StarshipConfig (TOML parse) │
│ ↓ │
│ print.rs → For each module in PROMPT_ORDER: │
│ ├── modules/<name>.rs → detect + render │
│ │ ├── config from configs/<name>.rs │
│ │ ├── StringFormatter (formatter/) │
│ │ └── exec_cmd for version/status │
│ └── rayon parallel execution │
│ ↓ │
│ segment.rs → Assemble final ANSI string │
│ ↓ │
│ stdout │
└──────────────────────────────────────────────────────────┘
Note
Starship is a pure CLI tool. There are no API endpoints, no HTTP server, no web interface, no background daemon. Every invocation is a fresh process that reads config, scans the environment, renders, and exits.
1.2 Core Subsystems
| Subsystem | Entry Point | Responsibility |
|---|---|---|
| CLI | src/main.rs |
Clap-based command dispatch for all subcommands |
| Library root | src/lib.rs |
Re-exports for library consumers |
| Config | src/config.rs |
TOML parsing, ModuleConfig trait, style parsing, StarshipConfig |
| Context | src/context.rs |
Shell detection, environment capture, git repo discovery, directory scanning |
| Modules | src/modules/mod.rs + src/modules/*.rs |
90+ feature modules, each self-contained |
| Module configs | src/configs/mod.rs + src/configs/*.rs |
One config struct per module with serde defaults |
| Formatter | src/formatter/ |
PEG-based template engine for format strings |
src/print.rs |
Prompt rendering, explain mode, timings, preset application | |
| Init | src/init/ |
Per-shell initialization scripts |
| Utilities | src/utils/ |
Command execution, file reading, home directory, env vars |
| Config editing | src/configure.rs |
starship config subcommand — update, toggle, print, edit |
| Bug report | src/bug_report.rs |
Diagnostic data collection |
| Logger | src/logger.rs |
File-based logging with session keys and auto-cleanup |
1.3 Data Flow: Module Execution
Each module follows a consistent pattern defined by the function signature:
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>>
The module:
- Loads its typed config struct (with
#[serde(default)]ensuring all fields have fallbacks) - Checks detection criteria — presence of specific files, file extensions, or folder names in the current directory (via
DirContents) - If detected, executes any needed external commands (e.g.,
node --version) withexec_cmdand the configuredcommand_timeout - Creates a
StringFormatterfrom its format string, maps variables to values - Returns
Some(Module)with styled segments, orNoneif detection fails or output is empty
1.4 Parallelism Model
Starship uses rayon for module-level parallelism. The thread pool size is controlled by the STARSHIP_NUM_THREADS environment variable. Most modules are fully independent — they read config, scan files, optionally run a command, and return segments.
The exception is git state: git_status and git_metrics share computed state via parking_lot synchronization primitives. This allows both modules to benefit from a single git repository scan without duplicating work.
2. System Requirements
2.1 Build Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| Rust toolchain | 1.90 (MSRV) | Latest stable |
| Rust edition | 2024 | 2024 |
| Cargo | Bundled with Rust | Latest stable |
| Git | Any recent | For shadow-rs build metadata |
2.2 Runtime Dependencies
Starship itself is a single static binary with no runtime library dependencies beyond the OS. However, individual modules may shell out to external tools:
| Category | Examples |
|---|---|
| Language runtimes | node, python, ruby, go, java, rustc, dotnet, elixir, etc. |
| Package managers | npm, cargo, pip, composer, gradle, etc. |
| Cloud CLIs | aws, gcloud, az, kubectl, terraform, etc. |
| VCS | git (also accessed via the gix crate natively) |
| System tools | cmake, docker, vagrant, etc. |
These are optional — modules that cannot find their target tool simply return None and produce no prompt segment.
2.3 Supported Shells
| Shell | Init Script | Notes |
|---|---|---|
| Bash | starship.bash |
precmd_function hook |
| Zsh | starship.zsh |
precmd hook |
| Fish | starship.fish |
fish_prompt function |
| PowerShell | starship.ps1 |
prompt function override |
| Elvish | starship.elv |
edit:before-readline hook |
| Nushell | starship.nu |
env/config integration |
| Cmd (Clink) | starship.lua |
Lua prompt filter |
| Tcsh | starship.tcsh |
precmd alias |
| Xonsh | starship.xsh |
$PROMPT callable |
2.4 Platform Support
| Platform | Status | Notes |
|---|---|---|
| Linux (x86_64, aarch64) | Full | Primary platform |
| macOS (x86_64, aarch64) | Full | .pkg installer available |
| Windows (x86_64) | Full | MSI/Chocolatey installers, deelevate + windows crate deps |
| FreeBSD | Supported | Via cargo install |
| WSL | Supported | WSLENV detection used in git_status |
Windows-specific dependencies in the build:
deelevatecrate — handles elevation detectionwindowscrate — Win32 API bindingswinres— embeds manifest and icon into the executable during build
Unix-specific:
nixcrate — POSIX API bindings
2.5 Cargo Features
| Feature | Default | Crate | Purpose |
|---|---|---|---|
battery |
Yes | starship-battery 0.11.0 |
Battery level/status module |
notify |
Yes | notify-rust 4.15.0 |
Desktop notifications (e.g., long-running command alerts) |
config-schema |
No | schemars 1.2.1 |
JSON Schema generation for config validation |
Build without optional features:
cargo build --release --no-default-features
Build with schema generation:
cargo build --release --features config-schema
3. Configuration Reference
3.1 Config File Location
Starship reads configuration from a single TOML file. Resolution order:
$STARSHIP_CONFIGenvironment variable (if set)~/.config/starship.toml(XDG default)
The file is parsed on every prompt invocation. There is no config caching between invocations — each process is ephemeral.
Important
Starship also supports JSONC format via
jsonc-parser 0.32.3for the config file, but TOML is the primary and recommended format. The config file path must point to a single file — directory-based config splitting is not supported.
3.2 Root Configuration Keys
These keys are set at the top level of starship.toml, outside any module section:
| Key | Type | Default | Description |
|---|---|---|---|
format |
String | "$all" |
Main prompt format. $all expands to all modules in PROMPT_ORDER |
right_format |
String | "" |
Right-aligned prompt (shells that support it) |
continuation_prompt |
String | (built-in) | Prompt shown for multi-line input continuation |
scan_timeout |
u64 | 30 |
Directory scan timeout in milliseconds |
command_timeout |
u64 | 500 |
External command execution timeout in milliseconds |
add_newline |
bool | true |
Print a blank line before the prompt |
follow_symlinks |
bool | (default) | Follow symlinks during directory scanning |
palette |
String (optional) | None |
Name of the active color palette |
palettes |
HashMap | {} |
User-defined color palettes (name to color map) |
profiles |
IndexMap | {} |
Named prompt profiles for quick switching |
$schema |
String | "" |
JSON Schema URL for editor validation |
The StarshipRootConfig struct is defined in src/configs/mod.rs. The PROMPT_ORDER constant (also in src/configs/mod.rs) defines the default expansion order for $all. The FullConfig struct aggregates the root config with all module configs for serialization.
3.3 Module Configuration Pattern
Every module has a corresponding config struct in src/configs/<module>.rs. All config structs share these conventions:
#[serde(default)]on every struct — ensures missing keys get sensible defaults#[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))]— conditional JSON Schema derivation- Fields typically include:
format,style,symbol,disabled, detection arrays (detect_files,detect_extensions,detect_folders)
Example pattern (representative):
[module_name]
format = "via [$symbol($version)]($style) "
symbol = "X "
style = "bold blue"
disabled = false
detect_files = ["Makefile"]
detect_extensions = ["mk"]
detect_folders = []
3.4 Style System
Styles are parsed in src/config.rs. A style string is a space-separated list of tokens:
Text attributes:
| Token | Effect |
|---|---|
bold |
Bold text |
italic |
Italic text |
underline |
Underlined text |
dimmed |
Dimmed/faint text |
inverted |
Swap foreground and background |
blink |
Blinking text |
hidden |
Hidden text |
strikethrough |
Strikethrough text |
Color specification:
| Format | Example | Description |
|---|---|---|
| Named color | red, green, blue |
16 standard terminal colors |
| Bright variant | bright-red, bright-green |
Bright/bold color variants |
| Hex | #FF5733 |
24-bit RGB color |
| ANSI 256 | 123 |
0-255 ANSI color index |
fg:<color> |
fg:red, fg:#FF5733 |
Explicit foreground (default if no prefix) |
bg:<color> |
bg:blue, bg:#003366 |
Background color |
prev_fg |
prev_fg |
Reference previous segment's foreground |
prev_bg |
prev_bg |
Reference previous segment's background |
Style strings compose naturally: bold italic fg:#FF5733 bg:black produces bold italic text with a custom orange foreground on a black background.
3.5 Format String Engine
The StringFormatter in src/formatter/string_formatter.rs processes format strings using a PEG grammar defined in src/formatter/spec.pest.
Syntax elements:
| Syntax | Meaning |
|---|---|
$variable |
Insert variable value |
[$text](style) |
Apply style to text |
($conditional) |
Only render if all variables inside are non-empty |
${module.sub} |
Reference a sub-module variable |
\\$ |
Literal $ (escaped) |
Format model types (from src/formatter/model.rs):
TextGroup— a styled group of format elementsFormatElement— individual text, variable, or conditionalStyleElement— style specification attached to a text group
Version formatting is handled separately by VersionFormatter in src/formatter/version.rs:
| Variable | Meaning |
|---|---|
${raw} |
Full version string as returned by the command |
${major} |
Major version component |
${minor} |
Minor version component |
${patch} |
Patch version component |
Example: version_format = "v${major}.${minor}" renders v3.12 from Python 3.12.1.
3.6 Custom Color Palettes
Palettes allow defining named colors that can be referenced in any style string:
palette = "catppuccin_mocha"
[palettes.catppuccin_mocha]
rosewater = "#f5e0dc"
flamingo = "#f2cdcd"
pink = "#f5c2e7"
mauve = "#cba6f7"
red = "#f38ba8"
Once a palette is active, its color names become valid in any style string: style = "bold mauve".
3.7 Prompt Profiles
The profiles key in root config stores named prompt configurations as TOML strings. These allow quick switching between different prompt layouts without editing the config file. The profiles field uses IndexMap<String, String> to preserve insertion order. A separate internal_profiles field exists but is skipped during serialization.
3.8 Config Editing Commands
The src/configure.rs module provides CLI-based config manipulation:
| Command | Action |
|---|---|
starship config |
Open config in $VISUAL or $EDITOR |
starship config <key> |
Print a config value |
starship config <key> <value> |
Set a config value |
starship toggle <module> |
Toggle a module's disabled state |
starship print-config |
Dump the full resolved config |
The config file is edited in-place using toml_edit 0.25.11, which preserves formatting, comments, and ordering.
4. Deployment & Scaling
4.1 Installation Methods
Shell script (Linux/macOS):
curl -sS https://starship.rs/install.sh | sh
The install script at install/install.sh handles platform detection, binary download, and placement.
Package managers:
| Platform | Command |
|---|---|
| Cargo | cargo install starship --locked |
| Homebrew | brew install starship |
| Scoop (Windows) | scoop install starship |
| Chocolatey | choco install starship |
| winget | winget install --id Starship.Starship |
| macOS .pkg | Built via install/macos_packages/ scripts |
| Windows MSI | Built via install/windows/ (WiX-based) |
4.2 Shell Integration
After installing the binary, each shell needs its init hook. The init scripts are embedded in the binary and emitted by starship init <shell>:
Bash — add to ~/.bashrc:
eval "$(starship init bash)"
Zsh — add to ~/.zshrc:
eval "$(starship init zsh)"
Fish — add to ~/.config/fish/config.fish:
starship init fish | source
PowerShell — add to $PROFILE:
Invoke-Expression (&starship init powershell)
Elvish — add to ~/.elvish/rc.elv:
eval (starship init elvish)
Nushell — generate config files:
mkdir ~/.cache/starship
starship init nu | save -f ~/.cache/starship/init.nu
Cmd (Clink) — install into Clink scripts directory:
starship init cmd
Tcsh — add to ~/.tcshrc:
eval `starship init tcsh`
Xonsh — add to ~/.xonshrc:
execx($(starship init xonsh))
The init logic in src/init/mod.rs uses StarshipPath to resolve the binary location and generates the appropriate hook registration for each shell.
4.3 Building from Source
git clone https://github.com/starship/starship.git
cd starship
cargo build --release
The release binary is at target/release/starship (or target/release/starship.exe on Windows).
Release profile (from Cargo.toml):
codegen-units = 1— maximum optimization (slower build, faster binary)lto = true— full link-time optimizationstrip = true— strip debug symbols
Bench profile:
codegen-units = 16— faster builds for benchmarkinglto = thin— lighter LTOstrip = false— keep symbols for profiling
4.4 Build Script Details
build.rs performs three tasks:
-
shadow-rs integration — embeds build metadata as compile-time constants:
PKG_VERSION— crate version fromCargo.tomlSHORT_COMMIT— abbreviated git commit hashBRANCH— git branch nameTAG— git tag (if on a tag)RUST_VERSION— Rust compiler version usedRUST_CHANNEL— stable/beta/nightlyBUILD_RUST_CHANNEL— channel used for the build itselfBUILD_TIME— timestamp of buildCLAP_LONG_VERSION— formatted version string for--version
-
Preset embedding — reads TOML preset files from
docs/public/presets/toml/and embeds them into the binary at compile time, enablingstarship preset <name>without file I/O at runtime. -
Windows resources —
winresembeds a Windows application manifest and icon into the.exe.
4.5 Packaging
macOS .pkg: Scripts in install/macos_packages/ build a signed macOS installer package.
Windows MSI: install/windows/ contains WiX Toolset definitions for building a Windows Installer package.
Chocolatey: Windows package definition also in install/windows/.
4.6 Distribution at Scale
Starship is a single binary with no server component. "Scaling" means distributing the binary to workstations. Common approaches for organizations:
- Package manager repositories (internal Artifactory, Chocolatey server, Homebrew tap)
- Configuration management (Ansible, Puppet, Chef) for binary placement + shell rc injection
- Dotfile repositories with the
starship.tomlchecked in - Container base images with Starship pre-installed (useful for dev containers)
- Shared
starship.tomlvia$STARSHIP_CONFIGpointing to a network-mounted or synced path
5. Operations
5.1 Environment Variables
Tip
All Starship-specific environment variables use the
STARSHIP_prefix. These are the primary operational knobs available without editing the config file.
| Variable | Purpose | Values |
|---|---|---|
STARSHIP_CONFIG |
Override config file path | Absolute file path |
STARSHIP_SHELL |
Override detected shell name | bash, zsh, fish, powershell, etc. |
STARSHIP_LOG |
Set log verbosity | trace, debug, info, warn, error |
STARSHIP_NUM_THREADS |
Set rayon thread pool size | Integer (default: CPU-dependent) |
STARSHIP_SESSION_KEY |
Session identifier for log files | String (auto-generated if unset) |
VISUAL |
Preferred editor for starship config |
Editor command (takes precedence over EDITOR) |
EDITOR |
Fallback editor for starship config |
Editor command |
PWD |
Current directory fallback | Path |
WSLENV |
WSL environment detection | Used by git_status for WSL-specific behavior |
TERM_PROGRAM |
Terminal emulator detection | e.g., iTerm.app, WezTerm |
LC_TERMINAL |
Terminal detection (alternative) | Terminal identifier |
TERM_PROGRAM_VERSION |
Terminal version detection | Version string |
LC_TERMINAL_VERSION |
Terminal version (alternative) | Version string |
5.2 Logging System
The logger (src/logger.rs) writes session-based log files to the platform-specific cache directory:
| Platform | Log Directory |
|---|---|
| Linux | ~/.cache/starship/ |
| macOS | ~/Library/Caches/starship/ |
| Windows | %LOCALAPPDATA%\starship\ |
Log files are named session_<STARSHIP_SESSION_KEY>.log. The session key is derived from STARSHIP_SESSION_KEY if set, otherwise auto-generated per shell session.
Log levels (set via STARSHIP_LOG):
| Level | Content |
|---|---|
error |
Fatal errors only |
warn |
Warnings and errors |
info |
Informational messages, warnings, errors |
debug |
Detailed debug output |
trace |
Maximum verbosity, includes all internal state |
Automatic cleanup: The logger implements old log file cleanup to prevent unbounded disk growth in the cache directory.
Tip
For diagnosing prompt rendering issues, run
STARSHIP_LOG=trace starship promptin the affected directory. The trace output shows every module's detection logic, command execution, and timing.
5.3 CLI Subcommands
The full CLI interface (from src/main.rs, clap derive mode):
| Subcommand | Purpose |
|---|---|
init <shell> |
Output shell initialization script |
prompt |
Render the prompt (called by shell hooks) |
module <name> |
Render a single module (for debugging) |
preset <name> |
Output or apply a built-in preset |
config [key] [value] |
Read, write, or edit configuration |
print-config |
Print the full resolved configuration |
toggle <module> |
Toggle a module's disabled state |
bug-report |
Generate a diagnostic bug report |
explain |
Print prompt with module explanations |
timings |
Print prompt with per-module timing data |
completions <shell> |
Generate shell completion scripts |
session |
Output a session key |
statusline |
Render status line output |
time |
(Hidden) Timing-related utility |
config-schema |
(Feature-gated: config-schema) Output JSON Schema for config |
5.4 Diagnostic Tools
Bug report (src/bug_report.rs):
starship bug-report
Collects system info, shell version, Starship version, config contents, and environment details into a formatted report suitable for GitHub issues.
Explain mode:
starship explain
Renders the prompt with annotations showing which module produced each segment and why.
Timings:
starship timings
Renders the prompt with per-module execution time, sorted by duration. Essential for identifying slow modules.
Single module test:
starship module git_status
Renders only the specified module — useful for isolating issues.
5.5 Presets
Presets are complete starship.toml configurations embedded at compile time from docs/public/presets/toml/. Apply with:
starship preset <preset-name> -o ~/.config/starship.toml
List available presets:
starship preset --list
Note
Applying a preset overwrites the entire config file. Back up your existing config first if you have customizations. Presets can also be piped:
starship preset <name> | catto inspect before applying.
6. Performance
6.1 Architecture Decisions for Speed
Starship's performance budget is tight — every millisecond of prompt render time is directly felt by the user. Key design choices:
- Rust with release LTO —
codegen-units=1andlto=truein the release profile maximize binary optimization at the cost of slower compilation - Parallel module execution — rayon processes independent modules concurrently across available cores
- Native git via gix —
gix 0.81.0provides in-process git operations (revision parsing, status, SHA computation) without shelling out to thegitbinary for many operations - Lazy evaluation —
std::sync::LazyLockdefers expensive version command execution until the value is actually needed - Directory scan with timeout —
DirContents::from_path_with_timeout()aborts scanning afterscan_timeoutmilliseconds, preventing hangs on large or network-mounted directories - Command timeout — every external command invocation (
exec_cmd) is bounded bycommand_timeoutmilliseconds - Single-pass rendering — the PEG parser processes format strings in a single pass
6.2 Tuning Parameters
| Parameter | Location | Default | Effect |
|---|---|---|---|
scan_timeout |
starship.toml root |
30 ms |
Max time for directory content scanning |
command_timeout |
starship.toml root |
500 ms |
Max time for any external command |
STARSHIP_NUM_THREADS |
Environment | CPU-dependent | Rayon thread pool size |
For slow prompts, the standard diagnostic workflow:
- Run
starship timingsto identify the slowest modules - Increase
command_timeoutif legitimate commands are being killed prematurely - Decrease
scan_timeoutif directory scanning is slow (network mounts, huge repos) - Disable modules you do not need: set
disabled = trueunder the module section - Set
STARSHIP_NUM_THREADSto match available cores if the default is suboptimal
6.3 Known Performance Considerations
Git operations in large repositories: The git_status module can be slow in repositories with many files or large working tree changes. The gix-based implementation is faster than shelling out, but still bounded by repository size.
Network-mounted directories: Directory scanning (DirContents) on NFS, SMB, or SSHFS mounts can block. The scan_timeout is the primary defense — set it aggressively low (10-15ms) on known-slow mounts and accept that some detection may be skipped.
PowerShell on Windows: PowerShell's process startup overhead amplifies Starship's per-prompt cost. This is a known issue (GitHub #2057). The command_timeout default of 500ms may be tight for some tools on Windows.
WSL git interop: The WSLENV detection in git_status handles the case where git operations cross the WSL/Windows boundary, which can be significantly slower than native operations.
6.4 Profiling
For development profiling, use the bench Cargo profile:
cargo build --profile bench
This uses codegen-units=16, lto=thin, and strip=false — faster build times with debug symbols preserved for profilers like perf, flamegraph, or cargo-instruments.
7. Security
7.1 Threat Model
Starship's security surface is minimal by design:
- No network access — Starship never makes network connections. All data comes from local filesystem, environment variables, and local command execution
- No persistent state — no databases, no caches between invocations, no IPC
- No elevated privileges — runs as the invoking user with no setuid or capabilities
- Read-only by default — only
starship configwrites to the filesystem (the config file only)
Warning
Starship executes external commands (version checks, git operations, etc.) with the permissions of the invoking user. A malicious
starship.tomlplaced in a shared or cloned repository could configure modules to trigger unintended command execution if the user pointsSTARSHIP_CONFIGto that file. Always review untrusted config files before use.
7.2 Configuration Security
The config file (starship.toml) is read from the user's home directory by default. Key security properties:
- Config is TOML — no code execution in the config parser itself
- Custom commands in modules (e.g., version commands) are executed via the standard command timeout mechanism
toml_editpreserves file structure but does not execute embedded code- No config file includes or imports — a single flat file only
- No remote config fetching — the config must exist on the local filesystem
Caution
The
STARSHIP_CONFIGenvironment variable can redirect config loading to any file path. In shared environments (multi-user servers, CI), ensure this variable is not set by untrusted profile scripts. A crafted config could define module format strings or custom command overrides that cause unintended behavior.
7.3 Environment Variable Exposure
Starship reads numerous environment variables for shell detection, terminal identification, and module behavior. In environments where environment variables contain secrets:
- Starship does not log environment variable values at
infolevel or below - At
debugandtracelevels (STARSHIP_LOG=debugorSTARSHIP_LOG=trace), environment state may be written to log files in the cache directory - Log files are written to the user's cache directory with standard user permissions
- The
bug-reportcommand collects environment information — review its output before sharing publicly
7.4 Build Supply Chain
Key dependencies for a security audit:
| Crate | Version | Risk Surface |
|---|---|---|
gix |
0.81.0 | Git protocol parsing, SHA computation |
toml / toml_edit |
1.1.2 / 0.25.11 | Config file parsing |
clap |
4.6.1 | CLI argument parsing |
regex |
1.12.3 | Pattern matching (ReDoS potential on malformed patterns) |
serde / serde_json |
1.0.228 / 1.0.149 | Serialization (no untrusted input in normal use) |
nu-ansi-term |
0.50.3 | ANSI escape sequence generation |
os_info |
3.14.0 | OS detection (reads /etc/os-release etc.) |
whoami |
2.1.1 | Username/hostname detection |
All dependencies are Rust crates from crates.io with standard Cargo.lock pinning.
7.5 Platform-Specific Security Notes
Windows: The deelevate crate detects whether the process is running elevated (administrator). The windows crate provides Win32 API access. Neither grants additional privileges beyond what the invoking user already has.
Unix: The nix crate provides POSIX API bindings. Starship does not use setuid, capabilities, or any privilege escalation mechanism.
8. Developer Internals
8.1 Source Layout
src/
├── main.rs CLI entry point (clap derive)
├── lib.rs Library root, re-exports
├── config.rs ModuleConfig trait, style parsing, StarshipConfig
├── context.rs Context struct (shell, env, git, dir scanning)
├── configure.rs Config editing (update, toggle, print, edit)
├── module.rs Module struct, ALL_MODULES constant
├── print.rs Prompt rendering, explain, timings, presets
├── segment.rs Segment struct (styled text unit)
├── bug_report.rs Bug report generation
├── logger.rs Session-based logging with auto-cleanup
│
├── configs/
│ ├── mod.rs StarshipRootConfig, PROMPT_ORDER, FullConfig
│ └── *.rs Per-module config structs (90+ files)
│
├── modules/
│ ├── mod.rs handle() dispatch, description()
│ ├── *.rs Per-module implementations (90+ files)
│ └── utils/ Directory scanning, path utils, truncation
│
├── formatter/
│ ├── mod.rs Formatter module entry
│ ├── model.rs TextGroup, FormatElement, StyleElement
│ ├── parser.rs PEG parser implementation
│ ├── spec.pest PEG grammar definition
│ ├── string_formatter.rs StringFormatter (template engine)
│ └── version.rs VersionFormatter
│
├── init/
│ ├── mod.rs Shell init logic, StarshipPath
│ ├── starship.bash
│ ├── starship.fish
│ ├── starship.zsh
│ ├── starship.ps1
│ ├── starship.elv
│ ├── starship.nu
│ ├── starship.lua
│ ├── starship.tcsh
│ └── starship.xsh
│
└── utils/
├── mod.rs exec_cmd, read_file, home_dir
├── env.rs Environment variable handling
├── serde.rs Custom TOML deserialization (ValueDeserializer)
└── statusline.rs Statusline utilities
8.2 Key Abstractions
Context (src/context.rs)
The Context struct is the central state object passed to every module. It encapsulates:
- Detected shell name and properties
- Environment variable access
- Current working directory
- Git repository discovery (via gix)
DirContents— cached directory scan results with timeout support- Reference to the parsed
StarshipConfig
Context is created once per prompt invocation and shared (by reference) across all module calls.
Module (src/module.rs)
The Module struct represents a rendered prompt component:
- Contains a name and a vector of
Segments - The
ALL_MODULESconstant lists every registered module name as a static array - The
handle()function insrc/modules/mod.rsdispatches to the correct module function by name description()returns a human-readable description for each module (used byexplain)
Segment (src/segment.rs)
A Segment is the atomic unit of prompt output — a styled text fragment. Each module produces zero or more segments. The print system concatenates all segments from all modules into the final prompt string with appropriate ANSI escape codes.
StringFormatter (src/formatter/string_formatter.rs)
The template engine that processes format strings:
- Parses the format string through the PEG grammar (
spec.pest) - Produces a tree of
FormatElementandTextGroupnodes - Resolves variables by calling registered mappers
- Handles conditionals —
($optional)blocks are omitted if any variable resolves to empty - Applies styles from
[$text](style)syntax
8.3 Module Development Pattern
To add a new module, four files must be touched:
-
Config struct — Create
src/configs/<module_name>.rs:use serde::{Deserialize, Serialize}; use crate::config::ModuleConfig; #[derive(Clone, Serialize, Deserialize)] #[cfg_attr(feature = "config-schema", derive(schemars::JsonSchema))] #[serde(default)] pub struct MyModuleConfig<'a> { pub format: &'a str, pub symbol: &'a str, pub style: &'a str, pub disabled: bool, pub detect_files: Vec<&'a str>, pub detect_extensions: Vec<&'a str>, pub detect_folders: Vec<&'a str>, } impl<'a> Default for MyModuleConfig<'a> { fn default() -> Self { MyModuleConfig { format: "via [$symbol($version)]($style) ", symbol: "X ", style: "bold blue", disabled: false, detect_files: vec!["my_file"], detect_extensions: vec!["myext"], detect_folders: vec![], } } } impl<'a> ModuleConfig<'a> for MyModuleConfig<'a> {} -
Module implementation — Create
src/modules/<module_name>.rs:use super::Context; use super::Module; pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> { // 1. Load config // 2. Check detection criteria via context.dir_contents() // 3. Execute commands if needed via context.exec_cmd() // 4. Create StringFormatter, map variables // 5. Return Some(module) or None } -
Registration — Add the module to:
ALL_MODULESinsrc/module.rshandle()dispatch match arm insrc/modules/mod.rsdescription()match arm insrc/modules/mod.rsPROMPT_ORDERinsrc/configs/mod.rs(if it should appear in$all)- Config re-export in
src/configs/mod.rs
-
Tests — Add tests in the module file or a dedicated test module
8.4 Testing
Test framework: Standard Rust #[test] with:
mockall 0.14.0— mock trait implementations for isolated testingtempfile 3.27.0— temporary directories for filesystem-dependent tests
Test patterns:
- Module tests create a temporary directory, populate it with detection files, build a
Context, and assert the module output - Config tests verify serde defaults and round-trip serialization
- Formatter tests verify PEG grammar parsing against known format strings
Run all tests:
cargo test
Run tests with a specific feature:
cargo test --features config-schema
8.5 Custom TOML Deserialization
src/utils/serde.rs implements ValueDeserializer — a custom TOML deserialization layer that enables Starship's module config pattern. This allows modules to define strongly-typed config structs with defaults while still accepting arbitrary TOML values from user configuration. The deserializer bridges TOML's dynamic value types to Rust's static type system.
8.6 Directory Scanning
The DirContents utility (src/modules/utils/) scans the current directory for files, extensions, and folder names. Key behavior:
DirContents::from_path_with_timeout(path, timeout)
- Respects the
scan_timeoutroot config value - Results are cached on the
Contextso multiple modules do not re-scan follow_symlinksconfig controls whether symbolic links are followed during traversal- Scanning provides O(1) lookups for file existence, extension presence, and folder name checks after the initial scan completes
8.7 Git Integration
Starship uses gix 0.81.0 with feature flags max-performance-safe, revision, status, and sha1:
- Repository discovery: Context locates the git repo by walking up from the current directory
- Status:
git_statusmodule reads modified/staged/untracked/conflicted counts - Metrics:
git_metricsshares state withgit_statusviaparking_lotto avoid redundant computation - Branch/commit: Read from git HEAD reference
The gix integration avoids shelling out to git for most operations, reducing per-prompt latency. External git may still be used for some edge cases not covered by the gix feature set.
8.8 Version Parsing
Version parsing uses two crates for maximum compatibility:
semver 1.0.28— strict SemVer parsing (for tools that produce compliant version strings)versions 7.0.0— lenient version parsing (handles non-SemVer output likePython 3.12.1,go version go1.22.0 linux/amd64)
This dual approach ensures modules can parse version output from virtually any command-line tool regardless of output format.
8.9 ANSI Terminal Output
Terminal output uses nu-ansi-term 0.50.3 for generating ANSI escape sequences and terminal_size 0.4.4 for detecting terminal dimensions. The rendering pipeline:
- Each
Segmentcarries aStyle(colors + attributes) nu-ansi-termconverts styles to platform-appropriate ANSI escape codes- Terminal width from
terminal_sizeis passed to modules that need to handle truncation or alignment
9. Integration Points
9.1 Shell Integration Details
Each shell init script in src/init/ follows a consistent pattern:
- Capture the starship binary path —
StarshipPathresolves the absolute path to avoid$PATHlookups on every prompt - Register hooks — each shell's native hook mechanism (precmd, PROMPT_COMMAND, fish_prompt, etc.)
- Pass prompt properties — exit status (
$?), command duration, number of background jobs, terminal width, vi-mode keymap - Call starship prompt — the hook invokes
starship promptwith the collected properties as command-line arguments - Capture right prompt — shells that support it also call
starship prompt --rightforright_format
The init_stub and init_main functions in src/init/mod.rs generate the shell-specific code, with the init scripts themselves stored as embedded string resources.
9.2 Git Repository Integration
Starship auto-discovers git repositories by walking up from the current directory. Multiple modules consume git state:
| Module | Git Data Used |
|---|---|
git_branch |
Current branch or detached HEAD |
git_commit |
Commit hash, tag |
git_state |
Rebase, merge, cherry-pick, bisect state |
git_status |
Modified, staged, untracked, conflicted counts |
git_metrics |
Added/deleted line counts (shares state with git_status) |
Note
The
git_statusandgit_metricsmodules share a single computation viaparking_lotsynchronization. Disablinggit_statuswhile keepinggit_metricsenabled will still trigger the shared git state computation. Disabling both saves the most time in large repositories.
9.3 Language/Tool Detection
Module detection is file-based. Each module defines arrays of filenames, extensions, and folder names to look for in the current directory via DirContents. Representative detection patterns:
| Module type | Detection Files | Detection Extensions | Detection Folders |
|---|---|---|---|
| Node.js | package.json, .node-version |
.js, .mjs, .cjs, .ts |
node_modules |
| Python | requirements.txt, pyproject.toml, setup.py |
.py |
|
| Rust | Cargo.toml |
.rs |
|
| Go | go.mod, go.sum |
.go |
Detection is performed via the cached DirContents scan, ensuring O(1) lookups after the initial directory scan completes within the scan_timeout window.
9.4 Terminal Detection
Starship detects the terminal emulator via environment variables:
TERM_PROGRAM— primary detection (e.g.,iTerm.app,WezTerm,vscode)LC_TERMINAL— alternative detection pathTERM_PROGRAM_VERSION/LC_TERMINAL_VERSION— terminal version information
This information is used by modules that adapt their output based on terminal capabilities (e.g., symbol rendering, color depth assumptions).
9.5 External Command Execution
The exec_cmd utility (src/utils/mod.rs) provides a standardized interface for modules to run external commands:
- Commands are executed with the user's environment
command_timeoutfrom root config bounds execution time- Output is captured (stdout) and returned as a string for the calling module to parse
- Failed or timed-out commands return
None, causing the module to silently produce no output
9.6 Cross-Module State Sharing
The primary instance of cross-module state is the git_status/git_metrics pair:
git_statusperforms the full git status computation- Results are stored in a
parking_lot-protected shared structure git_metricsreads from this shared state instead of recomputing
This pattern is intentionally limited to this single case. All other modules are fully independent, enabling safe parallel execution via rayon without synchronization overhead.
9.7 Known Issues (from GitHub)
| Issue | Description | Impact |
|---|---|---|
| #2057 | Slow prompt on PowerShell/Windows | Windows users experience higher latency due to PowerShell overhead |
| #7400 | git_status info/exclude not respected in worktrees | Git worktree users may see incorrect status |
| #7094 | Status module error display | Error codes may not render correctly in edge cases |
| #7403 | Tab completion in su -l |
Completions may not work after switching users |
| #6955 | macOS install issues | Platform-specific installation edge cases |
| #6763 | Catppuccin preset install error | Preset application may fail for this preset |
Note
These issues reflect the state of the repository at the documented commit. Check the GitHub issue tracker for current status and workarounds.
9.8 Documentation Site
The docs/ directory contains a VitePress-based documentation site with support for 20+ locales. This is a separate build artifact from the Starship binary itself and is deployed to starship.rs. The preset TOML files in docs/public/presets/toml/ serve double duty: they are the source for the documentation site and are embedded into the binary at compile time by build.rs.