skim

A fuzzy finder written in Rust — a faster, feature-rich alternative to fzf with a built-in TUI, multi-selection, and preview support.

skim (invoked as sk) is a fuzzy finder for the terminal written in Rust. It fills the same role as fzf — pipe any list of items into it and interactively filter down to a selection — but is implemented entirely in Rust, supports multi-line items, and has a built-in preview window with syntax highlighting when paired with bat.

Features

  • Fuzzy matching — type any substring of an item and skim filters the list in real time
  • Multi-select — press Tab to mark multiple items and pass them all to the output
  • Preview window — show a preview of the selected item (e.g. file contents via bat) in a split pane
  • Interactive mode — optionally run a command for each keystroke, enabling dynamic search over external data sources
  • fzf-compatible — supports most of fzf's command-line flags and FZF_DEFAULT_OPTS-style environment variables, making it a drop-in replacement in most scripts
  • Regex or fuzzy — toggle between fuzzy matching and exact regex matching at runtime
  • Colour themes — fully configurable colours via command-line flags or environment variables
  • Library API — can be used as a Rust library (skim crate) to embed fuzzy finding in your own applications

Installation

cargo install skim

Or via your system package manager:

# macOS
brew install skim

# Debian / Ubuntu (Debian 12+)
apt install skim

# Fedora
dnf install skim

# Arch Linux
pacman -S skim

# Nix
nix-env -iA nixpkgs.skim

Usage

# Fuzzy-find a file in the current directory tree
sk --ansi -c 'fd --type f'

# Pipe any list into skim
ls | sk

# Multi-select files and open them in your editor
vim $(fd -e rs | sk -m)

# With a preview window showing file contents
sk --preview 'bat --color=always {}'

# Fuzzy search git log
git log --oneline | sk

# Interactively search command history
history | sk

# Use as a directory changer
cd $(fd --type d | sk)

Shell integrations

Add to your shell config to replace the default history search:

# bash (~/.bashrc)
export SKIM_DEFAULT_OPTIONS="--reverse --height 40%"
source "$(sk --bash)"

# zsh (~/.zshrc)
source "$(sk --zsh)"

# fish (~/.config/fish/config.fish)
sk --fish | source

Ctrl+T file picker

# Insert a selected file path at the cursor
# Enabled automatically by the shell integration above

Alt+C directory jumper

# cd into a selected directory
# Also enabled by the shell integration

Key bindings

KeyAction
TypeFilter the list
/ or Ctrl+p / Ctrl+nMove up / down
TabToggle selection (multi-select mode)
Shift+TabDeselect item
EnterAccept selection
Esc / Ctrl+cCancel
Ctrl+aSelect all
Ctrl+dDeselect all
?Toggle preview window

Configuration

Set defaults via the SKIM_DEFAULT_OPTIONS environment variable:

export SKIM_DEFAULT_OPTIONS="
  --reverse
  --height 50%
  --preview 'bat --style=numbers --color=always {}'
  --preview-window right:60%
  --bind 'ctrl-f:page-down,ctrl-b:page-up'
"

Interactive mode

The -i / --interactive flag reruns a command for every keystroke, enabling dynamic external search:

# Search files using ripgrep interactively as you type
sk -i -c 'rg --color=always --line-number "{}"' \
   --ansi \
   --preview 'bat --color=always $(echo {} | cut -d: -f1)'

As a Rust library

cargo add skim
use skim::prelude::*;
use std::io::Cursor;

let options = SkimOptionsBuilder::default()
    .height(Some("50%"))
    .multi(true)
    .build()
    .unwrap();

let input = "item1\nitem2\nitem3".to_string();

let item_reader = SkimItemReader::default();
let items = item_reader.of_bufread(Cursor::new(input));

let selected = Skim::run_with(&options, Some(items))
    .map(|out| out.selected_items)
    .unwrap_or_default();

for item in selected {
    println!("{}", item.output());
}