Skip to content

It’s funny how deeply ingrained some tools can become in our workflows. Back around 2012, I stumbled upon Robby Russell's Oh My Zsh, and like many, it felt like a revelation. Suddenly, my terminal wasn't just a command line; it was this vibrant, supercharged environment. It was the gateway drug for many of us into the rich Zsh ecosystem, and for that, I'm genuinely grateful. It made the shell approachable and, dare I say, fun.

For over ten years, Oh My Zsh has been a steadfast companion. But as with all things in tech (and life!), needs evolve, perspectives shift, and sometimes, the tools that once felt indispensable start to feel a bit... much.

Its not you, its me: Why Consider a Change?

Oh My Zsh is fantastic, especially when you're starting out. It bundles: * An incredible array of plugins and themes. * Defaults that just work for a lot of common use cases. * A massive community, which means help is usually easy to find.

However, over time, I started noticing a few things. My shell startup wasn't as snappy as it could be. And if I'm honest, a lot of the power packed into Oh My Zsh was sitting idle. I had this feature-rich framework, but my day-to-day usage was pretty streamlined.

The real nudge, though, came from seeing newer tools like Starship pop up. They promised a more lightweight, focused approach, particularly for what I primarily cared about: a clean, informative, and customizable prompt. I realized my eyes were bigger than my stomach when it came down to zsh tooling. Less would be more.

Shell Audit: What Was I Actually Using?

Before I could even think about migrating, I had to do a bit of an audit. What parts of my Oh My Zsh setup were critical?

My plugin list looked something like this: * fabric * python * django * osx * battery * heroku * brew

And then there were my custom bits: * A tailored prompt showing username, hostname, current directory, and Git status. * Key integrations for tools I use daily: pyenv, asdf, fzf, terraform. * A collection of custom completions and aliases built up over the years.

Here’s the interesting part of this little research dive: I realized that many of the plugins I had enabled weren't actively doing much for me anymore. Much of the functionality I relied on (like completions for Python tools, Django commands, or Homebrew) was either: * Handled natively by Zsh itself once configured. * Provided by the standalone tools directly (e.g., pyenv and asdf manage their own shims and paths). * Easily replicated with a few lines in my .zshrc. * Not actively used on current projects

This was a bit of an "aha!" moment. The migration wasn't going to be about finding one-to-one replacements for a dozen plugins. It was about preserving my core environment and finding a better way to handle the prompt. This made the whole idea feel much less daunting.

The Migration Journey: An Exploration

My plan wasn't to rip everything out at once. That's a recipe for a frustrating afternoon. Instead, I approached it more like a research project:

  1. Preservation First (The Backup Mantra): No changes before backups. This is non-negotiable. bash cp ~/.zshrc ~/.zshrc.omz.backup cp ~/.zshenv ~/.zshenv.backup # If I had one with OMZ specific stuff # My dotfiles are version controlled, but a point-in-time copy is smart too cp -r ~/.dotfiles ~/.dotfiles.backup.omz-migration

  2. Introducing Starship: This felt like the core replacement. bash brew install starship Then, I started crafting ~/.config/starship.toml. The goal was to replicate the information from my old prompt, but with Starship's modern take. ```toml # ~/.config/starship.toml # Trying to get that familiar feel, but fresh! format = """ $username\ $hostname\ $directory\ $git_branch\ $git_status\ $character """

    [username] style_user = "red" format = "$user" show_always = true

    [hostname] style = "bold red" format = "@$hostname" ssh_only = false # I like seeing it always

    ... and so on for git, etc.

    The Starship docs are great for tweaking this.

The resulting shell:

sxalexander@evergreen dotsam.net dev *
  
Doesn't it just whisper "go ahead hero: type here"?
  1. Building a New Foundation (.zshrc): With Oh My Zsh temporarily out of the picture (by commenting out its source line), I started a minimal .zshrc. This involved:

    • Ensuring my history settings were preserved (I like a deep history).
    • Setting up directory navigation options (like autocd, pushd, popd).
    • Re-establishing my PATH and any essential environment variables.
    • Making sure the Zsh completion system was initialized correctly.
    • Integrating Starship: eval "$(starship init zsh)".
  2. The All-Important Test Drive: This was crucial. I opened new shell sessions and systematically checked if everything behaved as expected.

    • Could pyenv and asdf still manage my Python/Node/etc. versions?
    • Did fzf (Ctrl+R, Ctrl+T) still work its magic?
    • Were all my custom aliases and functions available?

    My checklist looked something like this: * [x] Directory navigation (autocd, pushd, popd) - Yep! * [x] Command history and search (Ctrl+R with fzf) - Working beautifully. * [x] pyenv & asdf functionality - All good. * [x] fzf fuzzy finding - Still my go-to. * [x] Java environment ($JAVA_HOME) - Correctly set. * [x] Custom PATH additions - All present.

  3. The Point of No Return (Almost): Uninstalling Oh My Zsh Once I was confident that my new, leaner setup covered all my bases, it was time. bash # Oh My Zsh provides an uninstaller, which is handy uninstall_oh_my_zsh I then double-checked for any lingering ~/.oh-my-zsh directories or OMZ-specific sourcing in my dotfiles and tidied up.

The result? A noticeably faster shell startup, a configuration that I feel I understand from top to bottom, and still, all the functionality I actually rely on. The migration was surprisingly smooth, largely because that initial "audit" phase revealed I wasn't as dependent on OMZ's plugin ecosystem as I thought.

Post-Migration: Fine-Tuning and Discoveries

Of course, no migration is truly "done" on the first pass.

Restoring Familiar Key Bindings: One thing I immediately missed was some of the Emacs-style key bindings that Oh My Zsh had set up. Easy fix in my .zshrc:

# Old habits die hard - need my Emacs bindings!
bindkey -e

bindkey "^A" beginning-of-line    # Ctrl+A: Move to beginning of line
bindkey "^E" end-of-line         # Ctrl+E: Move to end of line
bindkey "^U" kill-whole-line     # Ctrl+U: Kill whole line
# ... and a few others I rely on.

Future Explorations: This change has also opened up a few avenues I'm keen to explore: * Diving deeper into Starship's customization. There's a lot more it can do. * Potentially optimizing fzf further, maybe looking into specific configurations for things like iCloud Drive navigation.

Reflections on the Journey

This wasn't just about swapping out a tool; it was a useful exercise in understanding my own workflow. 1. Less is Often More: I reaffirmed that many of the "batteries included" features of large frameworks often go unused for seasoned developers who have more specific needs. 2. Modern Tools are Impressive: Starship is a great example of a focused, performant tool that does one thing really well. 3. Understanding the "Why": Stepping away from a framework like Oh My Zsh encourages a deeper understanding of Zsh itself. You start to see how things work under the hood. 4. Intentional Configuration: A minimal, purposeful setup is often faster and easier to maintain in the long run.

It's a bit like cleaning out a garage – you rediscover what's important, discard what's not, and end up with a more organized, efficient space. My shell feels that way now: lighter, faster, and perfectly tailored to what I need. No regrets about the decade with Oh My Zsh – it served its purpose wonderfully. But I'm excited about this new, more direct relationship with my Zsh setup.