git logo

The problem

Often times during development you keep environment variables that contain secrets used for development inside of your shell config, be it zsh, bash, or fish:

# inside .zshrc, .bashrc, or .fishrc
export MY_API_KEY=xxxx-xxxx-xxxxxxx

This is a problem if you version control your dotfiles as you’re going to end up saving secrets inside of git, which lead to quite a headache.

Solution A: Use a separate file for environment variables

You can use source to load another file from your shell config:

# Add this line to the end of your .zshrc, .bashrc, .fishrc (version controlled)
source ~/.zshrc.env

# Create a new file that will hold your secrets
$ touch ~/.zshrc.env

# Using the editor of your choice, add your secrets to this file
$ [vim|emacs|code] ~/.zshrc.env

# ~/.zshrc.env (not version controlled)
$ cat ~/.zshrc.env
export MY_API_KEY=xxxx-xxxx-xxxxxxx

Once you reload your shell, you will still have MY_API_KEY printed when running env! 🎉

# Restart your shell or simply reload it using `source`
$ source ~/.zshrc

# Let's verify
$ env | grep MY_API_KEY
MY_API_KEY=xxxx-xxxx-xxxxxx

Solution B: Use folder specific environment variables

A more advanced solution is to have environment variables be specific per-folder so that you can keep environment variables within the projects that use them. Whilst there are other options, we’re going to do this with direnv. Please note that this is not supported on Windows.

  1. Install direnv using your package manager of choice.

    # MacOS (homebrew)
    $ brew install direnv
    
    # Ubuntu
    $ apt get direnv
    
    # More examples in the link above...
    
  2. Hook it up to your shell:

    # Append to your .bashrc
    eval "$(direnv hook bash)"
    
    # Append to your .zshrc
    eval "$(direnv hook zsh)"
    
    # More examples in the link above...
    
  3. Set up environment variables for your project

    # Go into your project directory.
    $ cd ~/path/to/your/project
    
    # Create the file that will hold the environment variables.
    $ touch .envrc
    
    # Edit it with the editor of your choice, adding your variables. Whether to
    # prefix with "export" depends on your shell. If you don't see the
    # environment variables when running `env`, try adding or removing "export".
    $ [vim|emacs|code] .envrc
    
    # The contents of the .envrc
    $ cat .envrc
    export MY_API_KEY=xxxx-xxxx-xxxxxxx
    
    # Allow the .envrc file to be used.
    $ direnv allow .
    
  4. You’re all set! No shell reload required. 🎉

    # Let's verify
    $ env | grep MY_API_KEY
    MY_API_KEY=xxxx-xxxx-xxxxxx