| name | fd-find |
| description | Fast file name search with fd — correct pattern modes, type filters, ignore behavior, exec patterns, and common misuse to avoid |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":"developers","workflow":"search"} |
fd (fd-find) Skill
fd searches file names (and paths). It is Rust-based, respects .gitignore automatically, and traverses in parallel. Use it instead of find.
Mental Model
| Question | Answer |
|---|
| What does fd search? | File/directory names (not contents — use rg for contents) |
| Default pattern type | Regex against the filename (not full path) |
| Files skipped by default | Hidden files, .gitignore matches |
| How to search everything | -u or -HI |
Core Flags (Daily Use)
Pattern Modes
fd "pattern"
fd -g "*.rb"
fd -F "exact.name"
fd -p "src/.*spec"
fd -i "pattern"
fd -s "Pattern"
File Type Filters (-t)
fd -t f "pattern"
fd -t d "pattern"
fd -t l "pattern"
fd -t x "pattern"
fd -t e "pattern"
fd -t s "pattern"
fd -t p "pattern"
fd -t f -t l "pattern"
Important semantics:
-t x (executable) implies -t f — no need to add -t f
-t e (empty) matches both empty files AND empty dirs unless you also pass -t f or -t d
Extension Filter
fd -e rb
fd -e rb -e rake
Depth Control
fd -d 2 "pattern"
fd --min-depth 2 "pat"
fd --exact-depth 3 "pat"
Output
fd -a "pattern"
fd --format "{//}/{/}"
fd -0 "pattern"
Hidden Files + Ignore Behavior
fd skips by default:
- Hidden files/dirs (dotfiles)
.fdignore (per-directory)
.ignore
.gitignore (repo + global git config)
When fd "misses" something:
fd -H "pattern"
fd -I "pattern"
fd -u "pattern"
fd -HI "pattern"
fd --no-ignore-vcs "pat"
Custom ignore file: ~/.config/fd/ignore (global) or .fdignore (per-directory)
Excluding Results
fd -E "node_modules" "pattern"
fd -E "*.min.js" "pattern"
fd -E ".git" -E "tmp" "pattern"
Executing Commands on Results
-x — per file, parallel
fd -tf -x wc -l
fd -e rb -x rubocop {}
-X — once with all results (batch)
fd -e rb -X rg "TODO"
fd -tf -X wc -l
Placeholder syntax
| Placeholder | Meaning |
|---|
{} | Full path |
{/} | Basename |
{.} | Path without extension |
{/.} | Basename without extension |
{//} | Parent directory |
fd -e jpg -x convert {} {.}.png
fd -tf -x mv {} {//}/archive/
Ordering caveat
-x and -X results are non-deterministic (parallel traversal). Do not rely on order. For serial execution: --threads=1.
Common Misuse Patterns (AVOID)
❌ Using find instead of fd
find . -name "*.rb" -type f
fd -e rb -t f
❌ Using regex when you want glob (extension matching)
fd ".rb"
fd -e rb
fd -g "*.rb"
fd "\.rb$"
❌ Forgetting -p for path-based patterns
fd "spec/models"
fd -p "spec/models"
❌ Expecting -t e to mean only empty files
fd -t e
fd -t f -t e
fd -t d -t e
❌ Using -x and expecting ordered output
fd -tf -x process_file {}
fd -tf --threads=1 -x process_file {}
fd -tf | sort | xargs -I{} process_file {}
❌ Searching hidden files without -H
fd ".env"
fd -H ".env"
❌ Using -X with placeholders (they don't work with -X)
fd -e rb -X rubocop {}
fd -e rb -X rubocop
fd -e rb -x rubocop {}
❌ Passing extension with dot to -e
fd -e .rb
fd -e rb
❌ Expecting -g glob to match path separators without -p
fd -g "spec/models/*.rb"
fd -p -g "spec/models/*.rb"
Practical Recipes (GitLab Codebase)
fd -e rb -t f "spec" spec/
fd --changed-within 1d -t f
fd -t f -e rb . db/migrate/
fd -p "ee/app/models.*policy"
fd -t d -t e
fd -e yml -E vendor/
fd -e js -p "public/assets" -X rm
fd -t f --changed-within "$(git log -1 --format=%cd --date=iso)"
fd -i "user_policy"
fd -t x . bin/
Performance Tips
- Always pass a directory —
fd "pattern" src/ is faster than fd "pattern" .
- Use
-e for extension filtering — faster than regex with \.ext$
- Use
-E to exclude large dirs — fd -E node_modules -E .git "pattern"
-X (batch) is faster than -x (per-file) when running one command on many files
- Traversal is parallel by default — don't add
--threads=1 unless you need ordering