Ultimate Manual – Customizing the Bash Prompt on Ubuntu with Starship + Nerd Fonts

Boost your terminal with a fast, modern Starship prompt and a crisp Nerd Font. This guide shows how to install, configure, and customize everything for a clean, powerful, and visually smart command-line experience.

Ultimate Manual – Customizing the Bash Prompt on Ubuntu with Starship + Nerd Fonts
Photo by NASA / Unsplash

1. Why Spend Time on Your Prompt?

Reason What you get
Instant context See current directory, git branch, status, python/ruby/node env, kubernetes context, time, exit code, etc.
Reduced cognitive load No need to run pwd, git status, conda env list manually.
Speed A good prompt is rendered in < 5 ms, even on large repos.
Aesthetic joy Nerd‑font icons + colors make the terminal a pleasant place to work.
Consistency Same look across all your machines (desktop, laptop, WSL, remote SSH).

2. Prerequisites – What You Need on Ubuntu

Item Minimum version Install command
Ubuntu 20.04 LTS (or newer)
Bash 5.x (comes default)
Git 2.30+ sudo apt install git
curl / wget any sudo apt install curl wget
A Nerd Font any patched font see section 3
Starship latest release (v1.x) see section 4
Optional: bat, fd, ripgrep sudo apt install bat fd-find ripgrep
Optional: zsh or fish Not required, but useful for cross‑shell config.

NOTE: This guide assumes a pure Bash environment (no Oh‑My‑Bash, no PS1 hacks). If you already use a Bash framework, you can still follow the steps – just make sure to comment out the old PS1 assignments.

3. Step‑by‑Step: Install a Nerd Font

Nerd Fonts are patched fonts that embed thousands of icons (Font Awesome, Octicons, Powerline, etc.) used by Starship.

3.1 Choose a Font

Font Why you might like it Recommended size
FiraCode Nerd Font Monospaced, ligatures, great for code 11‑13 pt
Hack Nerd Font Classic coding font, high readability 11‑12 pt
JetBrainsMono Nerd Font Modern, tall glyphs, nice for UI 12‑13 pt
CaskaydiaCove Nerd Font (formerly Cascadia Code) Windows‑like, great for Powerline 12‑13 pt

3.2 Download & Install

You can install via the fonts-noto-color-emoji package or manually.

Method A – Using apt (Ubuntu 22.04+)

# Install the pre‑packaged Nerd Font from the Ubuntu repo (limited selection)
sudo apt update
sudo apt install fonts-firacode
# For the Nerd‑patched version:
sudo apt install fonts-firacode-nerd

The repo version may be outdated. For the latest glyph set, use Method B.

# Choose a version, e.g., JetBrainsMono
FONT_NAME="JetBrainsMono"
VERSION="2.304"   # check https://github.com/ryanoasis/nerd-fonts/releases for latest

mkdir -p ~/.local/share/fonts/nerd-fonts
cd ~/.local/share/fonts/nerd-fonts

wget "https://github.com/ryanoasis/nerd-fonts/releases/download/v${VERSION}/${FONT_NAME}.zip"
unzip "${FONT_NAME}.zip"
rm "${FONT_NAME}.zip"

# Update the font cache
fc-cache -fv

3.3 Set the Font in Your Terminal Emulator

Terminal How to set the font
GNOME Terminal Preferences → Profile → Text → Custom Font → select JetBrainsMono Nerd Font (or whichever you installed).
Tilix Right‑click → Preferences → Profiles → Text → Font.
Alacritty Edit ~/.config/alacritty/alacritty.yml: font: family: "JetBrainsMono Nerd Font"
Kitty font_family JetBrainsMono Nerd Font in ~/.config/kitty/kitty.conf.
WezTerm font = wezterm.font("JetBrainsMono Nerd Font") in ~/.wezterm.lua.
Tip: Enable “Allow bold text” and “Use built‑in rendering for Powerline symbols” if your emulator offers those options.

4. Step‑by‑STEP: Install & Configure Starship

4.1 What is Starship?

Starship is a cross‑shell, minimal, fast prompt written in Rust. It reads a single starship.toml file and prints a line of ANSI‑colored text that Bash (or any shell) can use as PS1.

4.2 Install the Binary

# Using the official script (recommended)
curl -fsSL https://starship.rs/install.sh | bash

# Or via Cargo (if you already have Rust)
cargo install starship

# Verify
starship --version

The installer puts the binary at ~/.cargo/bin/starship. Add it to your PATH if it isn’t already:

echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

4.3 Verify Execution

starship prompt
# Should output a short colored line (the prompt itself)

If you see command not found, double‑check the PATH entry and re‑source.

5. Integrating Starship with Bash

Open (or create) ~/.bashrc and add the following near the end before any custom PS1:

# -------------------------------------------------
# Starship Prompt – Begin
# -------------------------------------------------
# Load the Starship binary and initialise the prompt.
# The eval command is required because Starship prints a
# string that contains escape sequences.
if command -v starship > /dev/null; then
    # Optional: make Starship load faster by disabling certain modules here
    # export STARSHIP_CONFIG="$HOME/.config/starship.toml"
    eval "$(starship init bash)"
fi
# -------------------------------------------------
# Starship Prompt – End
# -------------------------------------------------

5.1 Reload

source ~/.bashrc

You should now see a very minimal prompt (just a line of a symbol). The rest of this manual will teach you how to make it useful and beautiful.

6. Deep‑Dive: The starship.toml Configuration File

Starship reads its configuration from $XDG_CONFIG_HOME/starship.toml (by default ~/.config/starship.toml). This file is fully TOML‑syntax and controls every module that appears in the prompt.

6.1 File Skeleton

# ~/.config/starship.toml

# -------------------------------------------------
# Global Settings
# -------------------------------------------------
[character]                # The prompt "character"
success_symbol = "[❯](bold green)"          # When the last command succeeded
error_symbol   = "[❯](bold red)"            # When the last command failed
vicmd_symbol   = "[❮](bold bright-black)"  # When in vi insert mode (if using vi mode)

[cmd_duration]             # Show how long the previous command ran
min_time = 2_000            # Show only if >2s (milliseconds)

[hostname]                 # Optional: show hostname on remote connections
ssh_only = true
format = "[$ssh_symbol]($style) [$hostname]($style) "

# -------------------------------------------------
# Git Section
# -------------------------------------------------
[git_branch]
symbol = "🌿 "               # Nerd Font branch icon
format = "[$symbol$branch]($style) "

[git_state]
rebase = "REBASING"
merge = "MERGING"
format = "[$state]($style) "

[git_status]
# Shows staged, unstaged, untracked, conflicted, etc.
format = "[$all_status]($style) "
conflicted = "⚔️"
ahead = "⇡${count}"
behind = "⇣${count}"
staged = "✚${count}"
unstaged = "✚${count}"
untracked = "…"

# -------------------------------------------------
# Language Runtimes
# -------------------------------------------------
[python]
symbol = "🐍 "
style = "bright-yellow"
format = "[$symbol($virtualenv)]($style) "

[nodejs]
symbol = "⚡ "
format = "[$symbol$v]($style) "

[golang]
symbol = "🐹 "
format = "[$symbol($version )]($style) "

# -------------------------------------------------
# Miscellaneous
# -------------------------------------------------
[time]
disabled = false
format = "[$time]($style) "
time_format = "%R"   # 24‑hour HH:MM

[status]
disabled = false
format = "[$symbol $status]($style) "

[custom.k8s]
command = "kubectl config current-context 2>/dev/null || echo ''"
when = "kubectl config current-context 2>/dev/null"
symbol = "⎈ "
style = "cyan"
format = "[$symbol($output)]($style) "

# -------------------------------------------------
# Palette – define colors once and reuse
# -------------------------------------------------
[palettes]
# Define a palette to avoid duplication
my_palette = { 
    primary = "bright-blue",
    secondary = "bright-black",
    success = "green",
    error = "red",
    warning = "yellow"
}
Tip: Use the starship explain command to get a JSON view of each module's default values.

6.2 Common Global Settings

Setting Description Example
add_newline Add an empty line before the prompt (makes it easier to read). add_newline
= true
scan_timeout How long (ms) Starship will wait for scanning the filesystem (git status, etc.). scan_timeout
= 30
command_timeout Global timeout for custom module commands. command_timeout
= 5000
format Full prompt layout – you can reorder modules or hide them completely. format
= "$username$hostname:
$directory
$git_branch
$git_status
$character"
right_format Modules that appear on the right side (requires a terminal that supports right‑aligned prompts). right_format
= "$time"

6.3 Understanding format Syntax

  • ${module} – a placeholder for a module defined elsewhere ([git_branch], [nodejs], etc.).
  • Literal text may be placed directly: "on " or " 🔧 ".
  • Colors can be added inline with ($style) or via a named palette: ($my_palette.success).

Example – a compact dev‑focused layout:

format = """
[┌](bold bright-black)$username$hostname $directory
[│](bold bright-black)$git_branch$git_status$python$nodejs$golang$kubernetes
[└](bold bright-black)$character
"""

The three‑line layout mimics Powerline but uses pure Unicode characters (╭─, │, ╰─) – you can replace them with Nerd‑Font glyphs (\ue0b0, \ue0b2, etc.) for a sleek look.

7. Common Modules & How to Tweak Them

Below is a module‑by‑module cheat sheet for developers. Each block shows the default values, typical customizations, and why you might want to change them.

Module What it Shows Default Symbol Typical Customization Example
character The prompt symbol (). (green on success) Use Powerline arrow, show vi‑mode symbol. success_symbol = "[➜](bold green)"
username Current user name. (if show_user enabled) Hide on local machine; show only on SSH. show_always = false
hostname Hostname (useful for remote sessions). Show only on SSH, shorten with ssh_only = true. ssh_only = true
directory Current working directory. Truncate deep paths, show git repo root. truncation_length = 3
git_branch Active git branch. Show detached HEAD with special style. symbol = " "
git_status Staged/unstaged changes, ahead/behind. Various icons. Hide untracked files to reduce noise. untracked = ""
git_state Rebase/merge/etc. REBASING etc. Use emojis for states. rebase = "🔄 "
cmd_duration How long last command took. took X secs Show only when > 1 s. min_time = 1000
status Exit code of previous command. (red) Show numeric code, or hide on success. symbol = "⚠️"
python Active virtualenv + version. Show only when inside venv. format = "[$symbol($virtualenv)]($style) "
nodejs Node version (node -v). Show only when package.json exists. detect_files = ["package.json"]
golang Go version (go version). Show go.mod detection. detect_files = ["go.mod"]
rust Rust version (rustc --version). Detect Cargo.toml. detect_files = ["Cargo.toml"]
java JDK version. Detect pom.xml or build.gradle. detect_files = ["pom.xml","build.gradle"]
kubernetes (custom) Current kubectl context. Show only when kubectl config exists. see custom module below
time Current time. None 24‑hour format, optional seconds. time_format = "%R:%S"
custom.* Anything you can script. Perfect for Docker, Terraform, etc. see section 8

7.1 Example: A “Powerline‑Style” format

format = """
[╭─](bold $palette.primary)$username$hostname $directory
[│](bold $palette.primary)$git_branch$git_status$python$nodejs$golang$kubernetes
[╰─](bold $palette.primary)$character
"""

How it works

  • The first line shows user/host and directory, prefixed by a Unicode “╭─”.
  • The second line prints git information and language runtimes.
  • The third line is the final prompt character.

Result (colors omitted for brevity):

╭─john@work ~/projects/starship-demo
│  main ⇡2 ⇣1  (venv)  1.22.5 ⎈ dev-cluster
╰─❯

8. Adding Your Own Custom Modules

Starship’s [custom.<name>] section lets you run any command and display its output, with conditions for when it should appear.

8.1 Anatomy of a Custom Module

Field Meaning Example
command Shell command to run. Must output a single line (no newlines). command = "git rev-parse --abbrev-ref HEAD"
when Optional test that decides if the module is rendered. when = "test -f Cargo.toml"
format How to render the output, with $output. format = "[$symbol($output)]($style) "
symbol Optional leading icon. symbol = "🚀 "
style Color/style. style = "bright-magenta"
shell Override default shell (bash). Useful for complex pipelines. shell = ["zsh", "-c"]
description Human‑readable description (used by starship explain). description = "Current Docker context"
command_timeout Override global timeout (ms). command_timeout = 2000
environment Set environment variables for the command. environment = [{ name = "DOCKER_HOST", value = "unix:///var/run/docker.sock" }]

8.2 Real‑World Examples

8.2.1 Docker Context

[custom.docker]
command = "docker context show 2>/dev/null || echo ''"
when = "docker context show 2>/dev/null"
symbol = "🐳 "
style = "cyan"
format = "[$symbol($output)]($style) "

8.2.2 Terraform Workspace

[custom.terraform]
command = "terraform workspace show 2>/dev/null"
when = "test -d .terraform"
symbol = "🛠️ "
style = "bright-yellow"
format = "[$symbol($output)]($style) "

8.2.3 AWS Profile

[custom.aws]
command = "aws configure get profile"
when = "aws configure get profile"
symbol = "☁️ "
style = "bright-blue"
format = "[$symbol($output)]($style) "

8.2.4 Battery Status (Linux)

[custom.battery]
command = "cat /sys/class/power_supply/BAT0/capacity"
when = "test -d /sys/class/power_supply/BAT0"
symbol = "🔋"
style = "green"
format = "[$symbol $output%]($style) "
Tip: Keep custom commands fast. Prefer reading a file (e.g., /proc/...) over spawning heavy CLI tools.

8.3 Debugging

# Use Starship's built‑in debug mode
starship explain
 Here's a breakdown of your prompt:
 "❯ " (<1ms)              -  A character (usually an arrow) beside where the text is entered in your terminal
 " 󰋞  " (<1ms)            -  The current working directory
 "@192.168.1.14 " (<1ms)  -  The currently assigned ipv4 address
 "   " (11ms)            -  The current operating system
 "  21:08 " (<1ms)       -  The current local time
 " pavel " (<1ms)         -  The active user's username

This prints a JSON object showing why the module was rendered or why it was skipped (missing file, timeout, etc.).

9. Color Schemes, Transparency & True‑Color

9.1 256‑Color vs True‑Color

  • 256‑color works everywhere (including older xterm). Use codes like bright-red, 247, #ff5f00.
  • True‑color (24‑bit) offers unlimited palette (#ff00ff). Most modern terminals (GNOME Terminal, Alacritty, Kitty, iTerm2) support it.

Starship automatically detects true‑color. You can force a mode:

[palette]
# Force 256‑color mode (useful for remote SSH to an old box)
# use_256_colors = true

9.2 Sample Palettes

Palette Name Primary Secondary Accent Error Warning Success
Dracula #ff79c6 #6272a4 #bd93f9 #ff5555 #f1fa8c #50fa7b
Solarized Dark #268bd2 #586e75 #b58900 #dc322f #cb4b16 #859900
Monokai Pro #ff6188 #2c2c2c #c5c8c6 #ff6188 #ffb86c #a9dc76

Define a palette in starship.toml:

[palettes.dracula]
primary = "#ff79c6"
secondary = "#6272a4"
accent = "#bd93f9"
error = "#ff5555"
warning = "#f1fa8c"
success = "#50fa7b"

Then reference it:

[character]
success_symbol = "[❯]($dracula.success bold)"
error_symbol = "[❯]($dracula.error bold)"

9.3 Transparent Background

Most terminals respect the background of the terminal window. If you use a transparent terminal, Starship’s colors will blend nicely. Just ensure you don’t set a background color in any module:

[character]
background = "none"

If a module accidentally sets a background, you can override globally:

[custom]
background = "none"

10. Performance Optimizations

Problem Fix
Prompt lags > 100 ms 1. Increase scan_timeout (default 30 ms).
2. Disable modules you don’t need
([git_status] disabled = true).
3. Use command_timeout for heavy custom modules.
Git status slow in huge repos Set git_status = { disabled = true }
and enable git_status =
{ ignore_submodules = true,
ignore_stash = true }
.
Network-dependent modules (e.g., AWS profile) Add when = "test -f ~/.aws/config"
to avoid hitting the network each prompt.
Repeated file reads Cache results via shell functions or
small scripts saved under
~/.cache/starship.
Example: a custom module that reads
~/.nvmrc
only once per directory change.
Too many custom modules Group related logic into a
single script that outputs
multiple symbols,
reducing the number of subprocesses.

Example: Global Fast‑Prompt Settings

# ~/.config/starship.toml
scan_timeout = 10
command_timeout = 500
add_newline = false
[git_status]
disabled = false
ignore_submodules = true
ignore_stash = true

11. Fallback & Compatibility

11.1 When Starship Can’t Load (e.g., Remote Minimal Box)

  1. Graceful degradation – Create a minimal starship.toml in ~/.config/starship.toml that only enables character and directory.

Detect missing binary – In ~/.bashrc:

if ! command -v starship &>/dev/null; then
    export PS1='\u@\h:\w\$ '
else
    eval "$(starship init bash)"
fi

11.2 Using Starship with Other Shells

  • Zsh: eval "$(starship init zsh)" in ~/.zshrc.
  • Fish: starship init fish | source.

All modules share the same config file, so you get a consistent look across shells.

11.3 Mixing with Oh‑My‑Bash / Bash‑It

If you already use a framework that sets PS1, you can either:

  • Disable the framework’s prompt (export OMB_PROMPT=off for Oh‑My‑Bash) and let Starship own the prompt.
  • Or wrap Starship inside the framework by calling starship prompt inside a custom segment.

12. Troubleshooting FAQ

Symptom Likely Cause Fix
Prompt shows raw escape sequences (\e[0m) Terminal doesn’t understand ANSI; $TERM mis‑set. Ensure export TERM=xterm-256color (or alacritty, xterm-truecolor).
Icons appear as boxes Nerd Font not selected in terminal. Re‑select the Nerd Font in terminal preferences, clear the font cache (fc-cache -fv).
Git status never appears git not installed or repo is huge. Install git. If repo is massive, set git_status = { disabled = true } or increase scan_timeout.
Prompt freezes for 5 s after cd into a directory with many files. Starship scanning for .git or custom module reading many files. Increase scan_timeout, or add when = "test -d .git" to git modules.
custom module always empty Command writes to stderr, or when condition fails. Append 2>/dev/null to command or remove the when. Use starship explain to see debug output.
Colors are wrong (e.g., bright yellow looks orange) Terminal color theme overrides. Use true‑color hex values (#ffdd00) for exact colors.
Prompt disappears after SSH Remote machine doesn’t have Starship installed. Install Starship on remote host, or configure starship init bash to fall back to a simple PS1.
starship command not found after source ~/.bashrc ~/.cargo/bin not in $PATH. Add export PATH="$HOME/.cargo/bin:$PATH" to ~/.bashrc before the Starship init block.
[character] shows a red ❯ even after successful command status module is still printing an error symbol. Ensure status module isn’t overriding character. Set disabled = true for [status] if you don’t want it.

13. Advanced Topics

13.1 Git Hooks to Speed Up Prompt

You can configure Git to cache status in a hidden file, reducing Starship’s scanning cost:

git config --global status.showUntrackedFiles no   # hide untracked files
git config --global core.preloadIndex true        # preload the index
git config --global gc.auto 0                     # disable auto‑gc in hot repos

13.2 Using Starship in CI (e.g., GitHub Actions)

When you run tests that log the prompt (rare), you might want a non‑interactive prompt:

steps:
  - name: Install Starship
    run: |
      curl -fsSL https://starship.rs/install.sh | bash
      echo 'eval "$(starship init bash)"' >> $HOME/.bashrc
  - name: Run script
    run: |
      source $HOME/.bashrc
      starship prompt   # prints the prompt string

Set add_newline = false for compact CI logs.

13.3 Multi‑Line Right‑Aligned Prompt

Starship can output a right‑aligned segment if your terminal supports it (\e[?7l / \e[?7h tricks).

right_format = "$time"

To make the right side appear on the same line (like Powerline), ensure your terminal supports the OSC 133 escape sequences (most modern terminals do). No extra config needed.

14. Resources, Cheat‑Sheets & Community

Resource Description
Official Docs https://starship.rs – complete module list, config reference, FAQ.
Nerd Fonts https://www.nerdfonts.com – download page, cheat‑sheet of icons.
Starship GitHub https://github.com/starship/starship – issue tracker, contribution guide.
Awesome Bash Prompt https://github.com/awesome-cli/awesome-cli#bash-prompt – curated list of prompt projects.
Color Palettes https://github.com/mbadolato/iTerm2-Color-Schemes – importable .itermcolors for many terminals.
Starship Discord #support channel – quick help from community members.
Bash Prompt Cheat‑Sheet https://github.com/awesome-cli/awesome-cli/blob/master/README.md#bash-prompt – quick reference for $PS1 syntax.
Vim/Neovim Integration set statusline=%{system('starship prompt')} – use Starship as a statusline in Vim.

Congratulations!

You now have a fully‑featured, fast, beautiful, and cross‑shell prompt powered by Starship and Nerd Fonts. Feel free to tweak the modules, symbols, and colors until the prompt feels like an extension of your workflow.

Happy hacking! 🚀

Read next