I've tried bash, zsh, and fish. After trying all three, I'm staying with fish. bash and zsh don't have sensible defaults, and configuring them is tedious. fish works great out of the box, and it's really fast. When I picked up zsh I used oh-my-zsh and later prezto, but it was slow and figuring out what everything all the framework did was complicated.

With fish I have a setup.fish script that defines all my universal exports, for when I setup a new computer. This is for private tokens, like HOMEBREW_GITHUB_API_TOKEN. For aliases and utilities, I wrote a fisherman [0] plugin. It has a functions folder and a fishfile for the few other plugins I use.

[0] https://github.com/fisherman/fisherman

I use fish too but I'm thinking about switching back to zsh. Mostly due to incompatible software here and there (like nvm) and lack of completions for a lot of cli tools.

asdf [0] is a great alternative to nvm. The best part is that it supports multiple languages and it's fast. I use the plugins for elixir, erlang, nodejs, and ruby.

Many CLI tools are missing completions, but I think it's slowly getting better over time. The pros outweigh the cons for me.

[0] https://github.com/asdf-vm/asdf

[1] https://github.com/fisherman/fisherman