Published: |
Dev tools on my macOS (2025)
Homebrew
https://brew.sh, alternatives to MacPorts, manual scripts and etc.
Despite Homebrew being released in 2009, it remains as the community default choice of package manager for macOS.
Personally, I like to use Homebrew with Brewfile
https://docs.brew.sh/Brew-Bundle-and-Brewfile. Instead of execute
commands like brew install neovim imperatively, I like to define them in a Brewfile and run brew bundle to install
them declaratively:
# Example Brewfilebrew "lsd"brew "neovim"brew "zellij"brew "mise"
# GUIscask "flux"cask "ghostty"cask "zed"The obvious benefit of this approach is we can backup the Brewfile and reinstall the packages on a new environment
whenever we need to.
Mise
https://mise.jdx.dev, alternatives to: asdf, nvm, pyenv and etc.
In the case of package management, I would recommend mise as the package version manager. What is a package version
manager? It’s a tool that allows us to manage different versions of a package on the same system. For example, if we
have multiple projects that require different versions of Node.js, we can use mise to switch between them easily. This
is not something that can be easily achieved with brew.
The way I use mise is by creating a mise.toml file at the root of each project:
[tools]node = "24"pnpm = "10"Or by executing the mise use command inside the project directory:
mise use node@24mise use pnpm@10The directory with mise.toml at its root will have the declared versions enabled within the project. If we switch to
another project with different tools or versions, mise will automatically switch.
The mise use --global <tool>@<version> command will create a global configuration file in ~/.config/mise/mise.toml
that will ensure the tools listed are available globally.
[tools]python = "3.13" # globally defined Python versionWhen to use mise vs brew?
If mise and brew can both install packages, why do I use them together?
While it is possible to use mise to manage everything (if the tool is available in its
registry). But personally, I still like to use brew for packages that I do not
care about their versions, such as git, curl, or jq. Plus, Brewfile have a greater selection of GUI applications
through brew cask. Therefore, my rules between mise and brew are:
- Use
misefor tools that I care about their versions, such asnode,pnpm, orpython. - Use
brewandBrewfilefor packages that I do not care about their versions, such asgit,curl, orjqand GUI applications likeghostty,raycast,orbstack, etc.
Fish Shell
https://fishshell.com, alternatives to zsh, bash and etc.
On modern macOS, zsh is the default shell. However, I prefer to use fish as my daily shell. When compared to zsh,
fish offers features like syntax highlighting, auto-completion, and a rich command history out of the box! We would
have to install zsh framework like on-my-zsh and a bunch of plugins to achieve the same baseline features as fish.
Btw, did I mention fish is now written in Rust? 🦀
Because I would like to have the latest stable version of fish, I install it through Brewfile:
brew "fish"Although I like fish very much, I do not set fish as my default shell. I keep zsh as the system default shell.
This is because as popular as fish is, most tools and scripts will most like not to have fish in mind, and are still
based on either bash or zsh. In the past, I had issues with fish conflicting with other tools (e.g., when running
automatic scripts), and now I would rather manually set fish as the shell in places where I need it. For example, in
the code editor Zed, I add the following lines in ~/.config/zed/settings.json to set fish as the default shell for
its integrated terminal:
"terminal": { "shell": { "with_arguments": { "program": "/opt/homebrew/bin/fish", "args": ["--login", "--interactive"] } }}Ghostty
https://ghostty.org, alternatives to alacritty, iterm2, warp and etc.
Only released in December 2024, Ghostty by Mitchell Hashimoto is already the go-to terminal emulator of many developers. It is written in the Zig language and it is honestly fast. Compared to other terminal emulators I’ve tried, Ghostty offers flawless performance and I really enjoyed the fact that Ghostty has built-in nerd fonts, it just makes so much sense.
Set fish as default shell in Ghostty
Find the Ghostty configuration file for example
$HOME/.config/ghostty/config and add in the following lines:
command = /opt/homebrew/bin/fish --login --interactiveshell-integration = fishRaycast
https://www.raycast.com, alternatives to Spotlight, Alfred, and etc.
The last tool on this list is also my most-used in terms of daily usage. Raycast replaces the sluggish Spotlight that came with macOS, but it offers a whole lot more than just a faster search tool. Some of its built-in or third-party extensions replace the need for other tools, and here are some of my favorites:
- Clipboard History. I bind it to shortcut
Cmd + Shift + C. - Window Management. This replaced Rectangle for me.
- Raycast AI (paid feature). My go-to AI assistant as with a simple shortcut
Option + Space, I can quickly open up a LLM chatbot with different models to choose from. - Raycast Notes. This also replaced the built-in macOS Notes app for me, as it offers developer friendly features like Markdown support and syntax highlighting etc.
This is not a exhaustive list of features of Raycast. There are so much more: Calculator, Currency Converter, Emoji Picker, Calendar Integrations, Shortcuts, Translate etc… I highly recommend you to check Raycast out if you haven’t already.
All Together
Here’s how I would setup the above tools after a fresh macOS installation:
1. Install homebrew
Open the default Terminal app, and paste in the installation script from https://brew.sh
2. Init Brewfile
Create Brewfile in ~/.config/Brewfile or your preferred location, and list out tools as brew or cask (Search on
the brew.sh website for clarifications):
brew "fish"brew "mise"cask "ghostty"cask "raycast"Run brew bundle within the ~/.config directory.
3. Setup fish in Ghostty
Follow the guide above to set fish as the default shell in Ghostty.
4. Use mise to manage package versions
For more project-dependent packages, like node, python and pnpm etc, we can:
# setup project-based versionsmise use node@24mise use python@3.13
# or setup globally versionsmise use --global node@24mise use --global python@3.135. Launch Raycast
Launch Raycast, configure to your needs, and be a 10x developer 🚀
There are so many other dev tools I use on a daily basis that I haven’t mentioned, for example: neovim, astronvim,
lazygit, starship, zellij, zed, orbstack and more, but I feel like they deserve a dedicated blog post so stay
tuned for my future blog posts 👀