I have recently moved to fish from bash. I'm immediately in love with the out-of-the-box functionality, but I'm a little bit at a loss when it comes to configuring the shell.

I've read through the documentation, particularly the section about initialization, and it states:

On startup, Fish evaluates a number of configuration files...

  • Configuration snippets in files ending in .fish, in the directories:
    • $__fish_config_dir/conf.d (by default, ~/.config/fish/conf.d/)
    • ...
  • User initialization, usually in ~/.config/fish/config.fish ...

So far, this is clear to understand. Coming from bash, I took my .bash_globals and .bash_aliases files, rewrote them a little bit according to fish's syntax, placed them into the ~/.config/fish/conf.d/ and they are loaded as expected.

However, when I looked over the contents of the config.fish file, I couldn't figure out anything that would need to be put there. To my understanding, fish is designed to work already out of the box, so the usual bash config like setting HISTCONTROL isn't necessary. Nor are the conf.d/ files called from some main script (like the .bash_aliases, etc., would be in .bashrc) - they're loaded automatically.

Is there some particular use case where config.fish is preferred - or even required - over conf.d/ files? So far, I would say individual files are cleaner to read, maintain and move between hosts. Is there some convention that's recommended to follow? Was there a specific motivation behind allowing so many levels of config, aside from giving users more freedom?

  • 2
    Note that neither .bash_globals nor .bash_aliases are standard bash features. I know Ubuntu creates this .bash_aliases file and sources it from .bashrc, so maybe some other Linux flavors also do it, but it has nothing to do with bash. I don't even know what .bash_globals is, probably something specific to whatever system you are using. Also, there is no need to set HISTCONTROL or anything else in bash. If you are happy with the defaults, you can leave them. It works perfectly well out of the box.
    – terdon
    Commented Mar 9, 2021 at 15:41
  • @terdon I see, thank you for the clarification! I'm most certainly overthinking this - I managed to get everything working so far - though I prefer knowing if there are any potential caveats, like (this is a made-up example) the non-interactive shell behaving differently, etc. Commented Mar 9, 2021 at 16:23
  • 1
    No caveats along those lines that I'm aware of - With either config.fish or conf.d/ files, you have the option of wrapping them in an if status is-interactive or if status is-login if there's something you would prefer to run only in those types of shells. Commented Mar 9, 2021 at 16:36
  • @NotTheDr01ds Might I ask for one extra detail? Is shebang required, or recommended in config.fish or the conf.d/ files? Commented Mar 9, 2021 at 16:40
  • 1
    I can't think of any use-case where a shebang would be needed in any of those files, for the same reason that it's not needed in bash startup scripts, err, configuration files. Note that fish does behave differently in at least one way from bash as described in that answer -- It does execute the startup files when executed with -c command. That's why I do like to wrap my startup files in if status is-interactive or if status is-login where appropriate. But it doesn't change the (lack of) need for a shebang in those files. Commented Mar 9, 2021 at 19:23

1 Answer 1


As far as purpose, I'd say there are several good reasons to support both.

First, and probably most importantly, as @Zanchey points out in the comments, conf.d support came about in release 2.3.0, so getting rid of config.fish at that point would have been a breaking change.

Second, as you said, freedom for the users to choose the way they would like to handle startup behavior.

Next, it's also somewhat "path of least resistance". I definitely share your preference for the modularity of conf.d/ files, and I love not having a config.fish myself. But some (perhaps even most) users who are moving over to fish for the first time default to the familiarity of a single .bash_profile-like place to put their config. I can imagine that the paradigm shift of not having a single-file config might be off-putting to some. In other words, config.fish helps provide a smooth migration for new users.

Further, config.fish is easier to explain to a new user, since it maps to something they already know in their previous shell. Even the fish FAQ defaults to telling users that config.fish is the equivalent of their previous startup scripts. Although I do wish they'd go on to explain the conf.d/ alternative as well there.

And config.fish does have one other small advantage, in that the execution order is more explicit (i.e. it's executed start to end). conf.d/ files are read just like any other conf.d/, in alphabetical order (or glob-result order, most likely). In my experience, this means that you have to resort to 00_dependency.fish type of naming to ensure that one file is run before others. That said, it should rare that anyone would have to resort to that.

As for "convention", well, I know many distributions set up their configuration files (e.g. the Apache2 httpd.conf) with a default "single-file" that goes on to process a conf.d/ structure. In fish's case, they just did away with the boilerplate for conffile in ~/.config/fish/conf.d/*.fish; source $conffile; end that would otherwise be required in config.fish.

  • 2
    Finally, config.fish has been available since forever, while conf.d was only added in 2.3.0 (released in 2016).
    – Zanchey
    Commented Mar 11, 2021 at 10:47
  • 1
    Thank you! I had been wondering about that when I wrote up the answer (having only been using fish for a couple of years now). I scanned the source and release notes. Thought I saw something about conf.d in the commit history that went back to 2012, but I was apparently wrong on that count. Now that you point me to the release, I see the "Add new directories for vendor functions and configuration snippets (#2498)" Edited that into the answer. Commented Mar 11, 2021 at 13:31
  • is there an easier way to source all files from a folder? I want to have a folder containing only secrets. So I can commit my ~/.config/fish to GitHub without secrets.
    – Ben Keil
    Commented Jan 15, 2022 at 3:36
  • 1
    @BenKeil - this is better asked as a separate question, but I recommend something like source ~/.private/fish/config.fish or for conf in ~/.private/fish/conf.d/*.fish; source $conf; end.
    – mattmc3
    Commented May 1, 2023 at 15:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .