Every Tool in My Terminal-First Dev Setup (2025)

Every Tool in My Terminal-First Dev Setup (2025)

Neovim, Wezterm, Tmux, and the rest — what survived two years of daily use and why I picked each one over the obvious alternatives.

Aayush BhartiAayush Bharti
/
11 min read

I switched to a terminal-first workflow two years ago and never looked back. The trigger was embarrassingly mundane: VS Code hit 2.4GB of RAM during a Next.js debugging session while I had Chrome DevTools open, and my laptop froze for thirty seconds mid-demo. That same week, I watched a coworker navigate a monorepo in Neovim faster than I could open the file picker in VS Code.

I felt slow. Not "I should optimize this" slow — "I'm fighting my own tools" slow. So I committed to replacing every GUI developer tool with a terminal-native equivalent and gave myself three months to get productive. Everything in this list survived a regular purge — if a tool doesn't make me measurably faster, it doesn't make the cut. Here's what stayed.

The core four: editor, terminal, shell, multiplexer

These are load-bearing walls. Swap out anything else and the system still works. Remove one of these and the whole workflow collapses.

Neovim

Neovim is the center of gravity. I moved from VS Code because I was tired of Electron eating memory and the constant extension update churn breaking my setup every few weeks. With native LSP support and Treesitter for syntax highlighting, I get the same intelligence features — autocomplete, go-to-definition, inline diagnostics — but startup takes 40ms instead of four seconds.

The real unlock was modal editing. Once you internalize that ciw replaces a word and dd deletes a line without reaching for the mouse, you stop thinking about text manipulation and start thinking about code. I use lazy.nvim for plugin management with about 35 plugins — telescope for fuzzy finding, nvim-cmp for completion, and conform.nvim for formatting on save.

The honest limitation: the learning curve is brutal for the first two weeks. You will be slower. You will want to quit. That investment in learning your tools deeply pays compound interest, but nobody tells you how bad week one feels.

Wezterm

Wezterm is a GPU-accelerated terminal emulator configured entirely in Lua. I tried Kitty first — solid performance, terrible config syntax. Alacritty flickered on Wayland and had no tab support. Wezterm nails both. The killer feature is scriptable keybindings: I have a Lua function that opens a new tab, cds into a project directory, and attaches the matching Tmux session in one keystroke. The config is a real programming language, not YAML or TOML, so conditionals and loops work naturally.

~/.config/wezterm/wezterm.lua
local wezterm = require("wezterm")
local config = wezterm.config_builder()

config.font = wezterm.font("JetBrains Mono", { weight = "Medium" })
config.font_size = 13.5
config.window_background_opacity = 0.95
config.hide_tab_bar_if_only_one_tab = true
config.window_padding = { left = 8, right = 8, top = 8, bottom = 8 }

-- quick project switcher: Ctrl+Shift+P opens FZF in a new tab
config.keys = {
  {
    key = "p",
    mods = "CTRL|SHIFT",
    action = wezterm.action.SpawnCommandInNewTab({
      args = { "bash", "-c", "cd $(find ~/Developer -maxdepth 2 -type d | fzf) && exec zsh" },
    }),
  },
}

return config

One annoyance: Wezterm's multiplexer mode is half-baked compared to Tmux. I stopped trying to replace Tmux with it and let each tool do what it's best at.

ZSH + Oh My Zsh

ZSH with Oh My Zsh is the shell layer. Bash's autocomplete is embarrassing in 2025 — no inline suggestions, no syntax highlighting as you type, no smart history search. ZSH's plugin ecosystem fixes all of that.

I run three plugins that matter: zsh-autosuggestions (ghost-text completion from your history), zsh-syntax-highlighting (red text when a command doesn't exist, green when it does), and git (aliases like gco for git checkout). The rest of Oh My Zsh I could take or leave. My .zshrc is 80 lines and loads in under 200ms — if yours takes longer, audit your plugins.

Tmux

Tmux handles session persistence and workspace organization. When my SSH connection drops or I close my laptop mid-debug session, Tmux keeps every pane, every running process, every scroll position alive. I tried Zellij for the modern UX and floating panes, but it crashed twice during production incident debugging — the one time you absolutely need your multiplexer to be rock solid. Tmux is boring and that's the point.

I have three persistent sessions: work, personal, and scratch. Prefix key is rebound to Ctrl+a (closer to home row than the default Ctrl+b), and I use tmux-resurrect to survive full system reboots. The only complaint is that Tmux's copy mode keybindings are arcane until you configure vi-mode.

Productivity and utilities

These sit between the core tools and fill the gaps. Each one replaced a slower workflow I didn't realize was slow until I timed it.

FZF

FZF is the single most impactful tool in this entire list. It's a general-purpose fuzzy finder that plugs into everything: Ctrl+T for file navigation, Ctrl+R for command history search, and inside Neovim via Telescope for project-wide file finding.

The speed difference is visceral — instead of cd-ing through four nested directories, I hit a keybind, type three characters, and I'm there. FZF's --preview flag with bat gives me file previews inline, so I can confirm I'm opening the right file before committing to it. Once you muscle-memory fuzzy finding, navigating a filesystem with ls and cd feels like using a flip phone after a smartphone.

FZF doesn't replace one tool. It replaces the concept of navigating to things manually. That mental shift is worth more than any individual config tweak.

Lazygit

Lazygit is a TUI for Git that makes interactive rebasing, conflict resolution, and cherry-picks tolerable. The raw Git CLI is powerful but punishing for complex operations — staging individual hunks requires remembering git add -p flags, interactive rebase means editing a file in your $EDITOR, and merge conflicts are a wall of angle brackets.

Lazygit gives me a split view: staged changes on one side, diff on the other, keybinds for every operation. I do simple commits from the command line and reach for Lazygit the moment anything gets interactive. The staging interface alone saves me five minutes per session on days with heavy Git work.

Bat and Btop++

Bat replaces cat with syntax highlighting, line numbers, and git diff markers. I aliased cat to bat globally and forgot about it — inspecting a package.json or skimming a config file now gives me highlighted output for free. Btop++ replaced htop for process monitoring. The GPU monitoring panel saved me during Three.js debugging when I couldn't figure out why my discrete GPU wasn't activating. Spotted the issue in ten seconds with Btop's GPU utilization graph. Both tools are zero-config improvements to built-in commands.

Better Commit

Better Commit enforces conventional commits without me memorizing the format every time. I tried Commitizen and found it slower with more prompts — Better Commit asks fewer questions and gets out of the way faster. If you're working on a project with CI that validates commit messages (and you should be), this eliminates the "oops, wrong prefix" cycle.

Shell replacements that compound daily

These are modern rewrites of Unix coreutils. Individually, each saves a few seconds. Collectively, they reshape how you interact with the filesystem. Small friction reductions compound — I estimated these save me 15-20 minutes per day across hundreds of small interactions.

eza replaces ls with git-aware file listings, icons, and tree views built in. eza -la --git shows me file permissions, sizes, and git status in one shot. I aliased ls to eza and tree to eza --tree — two commands replaced with one tool that does both better.

zoxide replaces cd with frecency-based directory jumping. Type z portfolio from anywhere on the system and it jumps to ~/Developer/aayush/next-portfolio because that's the directory matching "portfolio" I visit most often. It learns your habits. After a week of normal use, I stopped typing full paths entirely.

ripgrep (rg) replaces grep and it's not close. Ripgrep is faster, respects .gitignore by default (no more sifting through node_modules results), and supports PCRE2 regex. For building this blog with MDX, I use rg constantly to search across content files and component code simultaneously.

delta makes git diff output actually readable. Syntax-highlighted diffs with line numbers, side-by-side view mode, and proper word-level change highlighting. Set it as your git pager once and every diff command benefits automatically.

Four aliases — ls, cd, grep, cat — all pointing to faster tools. Same muscle memory, better output. That's the ideal upgrade path.

API and database tools

I burned out on Postman's bloat (500MB for an HTTP client, really?) and switched to terminal-native alternatives. These two cover 95% of what I need without Electron.

Posting is Postman as a TUI. API collections are plain text files I can version-control, diff, and share through Git. It starts in under a second. No account required, no cloud sync, no team-tier upsell. For testing endpoints during development, it's everything I need and nothing I don't.

Harlequin is a lightweight SQL client that works with Postgres, SQLite, and DuckDB. I was using DataGrip but the JetBrains startup time was killing quick database checks — "let me verify this query" shouldn't require waiting 15 seconds for a Java app to boot. Harlequin is instant, keyboard-driven, and has autocomplete for table and column names.

How it all connects: a real workflow

The individual tools matter less than how they compose. Here's what a typical coding session looks like end to end.

I open Wezterm. Tmux automatically attaches my last session — three windows already arranged: editor, server, and git. I hit Ctrl+Shift+P to open my project switcher (FZF scanning ~/Developer), type "port" to fuzzy-match my portfolio repo, and I'm in the project root.

Neovim opens with Telescope ready. I type <leader>ff, search for the component I need to change, and LSP has diagnostics loaded before my fingers leave the keyboard. After making changes, I split a Tmux pane, run the dev server, and preview in the browser.

When I'm ready to commit, lg aliases to Lazygit — I stage hunks visually, write a conventional commit message with Better Commit, and push. The diff shows up syntax-highlighted via delta. The entire flow from "open terminal" to "pushed commit" never touches a mouse.

The philosophy is home-row efficiency. Every mouse reach is a context switch, and context switches are where focused work goes to die.

That's not theoretical. I timed my workflow before and after the migration. Common operations — finding files, switching projects, staging commits, checking processes — dropped from an average of 8 seconds to under 2. Across a full workday, that's a non-trivial amount of reclaimed focus time.

What didn't survive the cut

Not everything I tried made it. The purge is the most important part of this system — adding tools is easy, removing them requires honesty about what's actually useful versus what looks cool in a dotfiles screenshot.

Neofetch/Fastfetch — Fun for exactly one screenshot. After that, it's a startup script that adds 200ms to every new terminal for information I never look at. Removed after a week.

Cava — Audio visualizer in the terminal. Beautiful, completely useless for development work. I kept it for two months because it looked good on r/unixporn. Vanity tool.

Hyprshot — Screenshot utility for Hyprland. Replaced with a three-line shell script using grim and slurp that does exactly what I need without another dependency.

Starship prompt — Feature-rich cross-shell prompt. Looked great, added 150ms to prompt rendering. I switched to a minimal custom prompt in my .zshrc that shows git branch and exit code. Nothing else.

Fig (now Amazon Q) — Autocomplete overlay for the terminal. Clever idea, terrible execution. It intercepted keystrokes, conflicted with FZF, and the AI suggestions were wrong often enough to be distracting rather than helpful. Uninstalled after three days.

The terminal as an investment

Two years in, the productivity gains are real but they're not the main reason I stayed. The deeper value is understanding what your tools are doing. GUI applications hide complexity behind buttons and dropdowns. Terminal tools expose it.

When your build fails, you see the exact command that ran. When your git history is wrong, you see the exact sequence of operations. That transparency makes you a better debugger, a better systems thinker, and — counterintuitively — faster at fixing problems even in GUI-heavy environments because you understand the underlying primitives.

The honest cost: the first month was slower. Significantly slower. I had to look up keybindings constantly, my Neovim config broke weekly, and I missed VS Code's "it works out of the box" convenience. If you're considering this switch, budget real time for the transition and don't do it the week before a deadline. The payoff comes, but it's not instant.

I'm watching a few tools for potential additions: Ghostty as a Wezterm alternative (Zig-based, extremely fast, but still maturing), Helix as a post-Vim modal editor (built-in LSP, no plugin management, but the ecosystem is thin), and Claude Code CLI for AI-assisted development directly in the terminal without leaving my workflow.

The filter stays the same — if it doesn't make me measurably faster after two weeks of honest use, it gets cut. Speed and home-row efficiency aren't preferences. They're the architecture of how I work.

Command Menu

Search pages, blog posts, projects, and more.