What directory structure and files does mix create?

I’ve been using mix to fetch some code and use it in a project.
I’ve used three commands so far:

mix new <dir>

After mix new I edited mix.exs to include a dependency. Then did

mix deps.get
mix deps.compile

This created 17 directories and 40 files. The manual page for mix says what these commands do - but what I’m interested in is a specification of the exact directory structure created by these comand and the contents of the different files. Is this documented somewhere?

Also are the files fetched with dep.get stored under the <Dir> directory, or are they hidden away somewhere else?

If I create two projects with mix new a and mix new b and add the same dependencies to a and b will I get two copies of the dependecies or will they be shared somehow?

1 Like

Dependencies retrieved by mix are extracted into the deps/ folder. The downloaded bundle is also cached somewhere by mix, so on subsequent mix deps.get for the same dependency it’s not going to hit the network again.

So in your example you should end up with your dependencies’ (mix-)projects extracted into both a/deps/ and b/deps/ separately and the downloaded artefact of those dependencies somewhere in your filesystem.

What I don’t know for sure is if that’s all what’s being added :smiley:

deps/ does contain the sources of downloaded dependencies. At least for hex packages there is also a cache of tarballs in ~/.mix AFAIK.

Compiled dependencies do live under _build/$MIX_ENV/$PACKAGE_NAME.

“somewhere in your filesystem” is not good.

I really would like a specification of where all the files that mix creates are and what they do - documenting the commands and not how they manipulate the file system is only half the story.

1 Like

Most of this stuff is considered an implementation detail and could change with any version, but in general mix should not do anything outside of your project root or of ~/.mix.

It’s actually ~/.mix unless you define MIX_HOME env. That’s what most ppl doesn’t do

So all dependencies are downloaded into /deps folder of the project. Compiled files are placed in _build and that follows mostly the standard OTP release structure (it has some additional files like consolidated protocol modules, build cashes and manifests for incremental compilation). All of those paths are configurable in mix.exs (and this is used, for example, in umbrella projects to share those folders among multiple applications).

There’s an additional cache for packages so that you don’t need to download them every time - this is in ~/.mix by default, but it is controlled by MIX_HOME variable as was mentioned.

Finally, it’s generally not safe to share the compiled files between projects. Because of macros and dynamic compilation, how a module is compiled can be changed by project configuration. This means just the module name is not enough to determine if it will contain the same code.

4 Likes

I hope this is true - unfortunately my disk is full of implementation details.

When applications start scattering their files all over the place without telling me I get rather annoyed. A quick peep in my ~/Library/Application Support directories (on a mac) shows I have 10’s of GB of data left there and in some cases by programs I had thought to have deleted.

Many programs have zero ability to clean up after themself in case you want to delete them, or re-install them if things go wrong.

Does mix clean delete everything?

I guess I’d really like a mix delete.everything that deleted everything that had been pulled into the system and hidden away (including mix :slight_smile:

Also mix where.is.everything if you see what I mean

1 Like

mix clean does only clean artifacts of your application from _build, mix deps.clean will clean build artifacts from _build, but none of those will actually wipe the cache located at $MIX_HOME :frowning:

I do feel you pain though… Often when I de-install some piece of software I have to look into ~/.$APP_NAME and ~/.config/$APP_NAME for leftovers. This is annoying and I really whish there were better diocumentation about this behaviour, especially when software does not adhere to the convention to use one of those places but does totally do its own thing.

I often have to guess then ;(

So if you do a feature request that asks for more clarity about how and when and which files or folders are created I’ll support you!

The problem with tasks like delete.everything or where.is.everything is that it’s very hard (if not impossible) to both implement them and keep the system extensible.

Mix has the concept of compilers defined through a behaviour that are responsible for “compiling” the project (and that notion is very broad). There are couple built-in compilers (for elixir, erlang, leex, yecc, app file, xref analysis, etc). But the notion is extensible, so other projects can also extend what happens when you run mix compile - and this is leveraged by things like the gettext package to extract translation data or phoenix to compile HTML templates to modules and functions. Anybody can define a new compiler and run it, and the compiler can run arbitrary code - how would you track what files it writes? The only thing you can do is have some conventions and that’s what mix does with deps and _build.

1 Like

Hex stores packages cache in $HEX_HOME/packages ($HEX_HOME defaults to ~/.hex).

The docs about this are improved on master [1] and when the next release is out, we’ll also update it on website: https://hex.pm/docs/tasks#hex_config

So, if a user wishes to store app specific stuff in ~/.config/ it’s totally possible by using MIX_HOME and HEX_HOME env variables. I agree it would be nice if the user can learn about these env variables sooner.

In next release we’re also adding more debugging info e.g. when fetching package from cache:

~/foo% MIX_DEBUG=1 mix deps.get
** Running mix loadconfig (inside Foo.MixProject)
** Running mix deps.get (inside Foo.MixProject)
** Running mix archive.check (inside Foo.MixProject)
Resolving Hex dependencies...
Dependency resolution completed:
  mime 1.1.0
* Getting mime (Hex package)
  Using locally cached package (/Users/wojtek/.hex/packages/hexpm/mime-1.1.0.tar)

However, you kinda need to know there’s a MIX_DEBUG=1 option so we’ll look into improving discoverability of this. Also, we’re not telling users when we’re saving stuff into cache.

[1] https://github.com/hexpm/hex/blob/4b9b8/lib/mix/tasks/hex.config.ex#L36

5 Likes

For Windows, Mix.install compiled deps to %USERPROFILE%\AppData\Local\mix\Cache\installs\elixir-1.16.0-erts-14.2.1.