# `Mix`
[🔗](https://github.com/elixir-lang/elixir/blob/55da97b9a329638ed5dfdbb1f8e10c9895829655/lib/mix/lib/mix.ex#L5)

Mix is a build tool that provides tasks for creating, compiling,
and testing Elixir projects, managing its dependencies, and more.

## `Mix.Project`

The foundation of Mix is a project. A project can be defined by using
`Mix.Project` in a module, usually placed in a file named `mix.exs`:

    defmodule MyApp.MixProject do
      use Mix.Project

      def project do
        [
          app: :my_app,
          version: "1.0.0"
        ]
      end
    end

See the `Mix.Project` module for detailed documentation on Mix projects.

Once the project is defined, a number of default Mix tasks can be run
directly from the command line:

  * `mix compile` - compiles the current project
  * `mix test` - runs tests for the given project
  * `mix run` - runs a particular command inside the project

Each task has its own options and sometimes specific configuration
to be defined in the `project/0` function. You can use `mix help`
to list all available tasks and `mix help NAME` to show help for
a particular task.

The best way to get started with your first project is by calling
`mix new my_project` from the command line.

## `Mix.Task`

Tasks are what make Mix extensible.

Projects can extend Mix behaviour by adding their own tasks. For
example, adding the task below inside your project will
make it available to everyone that uses your project:

    defmodule Mix.Tasks.Hello do
      use Mix.Task

      def run(_) do
        Mix.shell().info("Hello world")
      end
    end

The task can now be invoked with `mix hello`.

See the `Mix.Task` behaviour for detailed documentation on Mix tasks.

## Dependencies

Mix also manages your dependencies and integrates nicely with the [Hex package
manager](https://hex.pm).

In order to use dependencies, you need to add a `:deps` key
to your project configuration. We often extract the list of dependencies
into its own function:

    defmodule MyApp.MixProject do
      use Mix.Project

      def project do
        [
          app: :my_app,
          version: "1.0.0",
          deps: deps()
        ]
      end

      defp deps do
        [
          {:ecto, "~> 2.0"},
          {:plug, github: "elixir-lang/plug"}
        ]
      end
    end

You can run `mix help deps` to learn more about dependencies in Mix.

## Environments

Mix supports different environments. Environments allow developers
to prepare and organize their project specifically for different
scenarios. By default, Mix provides three environments:

  * `:dev` - the default environment
  * `:test` - the environment `mix test` runs on
  * `:prod` - the environment your dependencies run on

The environment can be changed via the command line by setting
the `MIX_ENV` environment variable, for example:

```bash
$ MIX_ENV=prod mix run server.exs
```

You can also specify that certain dependencies are available only for
certain environments:

    {:some_test_dependency, "~> 1.0", only: :test}

When running Mix via the command line, you can configure the default
environment or the preferred environment per task via the `def cli`
function in your `mix.exs`. For example:

    def cli do
      [
        default_env: :local,
        preferred_envs: [docs: :docs]
      ]
    end

The environment can be read via `Mix.env/0`.

## Targets

Besides environments, Mix supports targets. Targets are useful when a
project needs to compile to different architectures and some of the
dependencies are only available to some of them. By default, the target
is `:host` but it can be set via the `MIX_TARGET` environment variable.

When running Mix via the command line, you can configure the default
target or the preferred target per task via the `def cli` function
in your `mix.exs`. For example:

    def cli do
      [
        default_target: :local,
        preferred_targets: [docs: :docs]
      ]
    end

The target can be read via `Mix.target/0`.

## Configuration

Mix allows you to configure the application environment of your application
and of your dependencies. See the `Application` module to learn more about
the application environment. On this section, we will focus on how to configure
it at two distinct moments: build-time and runtime.

> #### Avoiding the application environment {: .warning}
>
> The application environment is discouraged for libraries. See Elixir's
> [Library Guidelines](https://elixir.hexdocs.pm/library-guidelines.html) for
> more information.

### Build-time configuration

Whenever you invoke a `mix` command, Mix loads the configuration
in `config/config.exs`, if said file exists. It is common for the
`config/config.exs` file itself to import other configuration based
on the current `MIX_ENV`, such as `config/dev.exs`, `config/test.exs`,
and `config/prod.exs`, by calling `Config.import_config/1`:

    import Config
    import_config "#{config_env()}.exs"

We say `config/config.exs` and all imported files are build-time
configuration as they are evaluated whenever you compile your code.
In other words, if your configuration does something like:

    import Config
    config :my_app, :secret_key, System.fetch_env!("MY_APP_SECRET_KEY")

The `:secret_key` key under `:my_app` will be computed on the host
machine before your code compiles. This can be an issue if the machine
compiling your code does not have access to all environment variables
used to run your code, as loading the config above will fail due to the
missing environment variable. Furthermore, even if the environment variable
is set, changing the environment variable will require a full recompilation
of your application by calling `mix compile --force` (otherwise your project
won't start). Luckily, Mix also provides runtime configuration, which is
preferred in such cases and we will see next.

### Runtime configuration

To enable runtime configuration in your release, all you need to do is
to create a file named `config/runtime.exs`:

    import Config
    config :my_app, :secret_key, System.fetch_env!("MY_APP_SECRET_KEY")

This file is executed whenever your project runs. If you assemble
a release with `mix release`, it also executes every time your release
starts.

## Aliases

Aliases are shortcuts or tasks specific to the current project.

In the [Mix.Task section](#module-mix-task), we have defined a task that would be
available to everyone using our project as a dependency. What if
we wanted the task to only be available for our project? Just
define an alias:

    defmodule MyApp.MixProject do
      use Mix.Project

      def project do
        [
          app: :my_app,
          version: "1.0.0",
          aliases: aliases()
        ]
      end

      defp aliases do
        [
          c: "compile",
          hello: &hello/1,
          paid_task: &paid_task/1
        ]
      end

      defp hello(_) do
        Mix.shell().info("Hello world")
      end

      defp paid_task(_) do
        Mix.Task.run("paid.task", [
          "first_arg",
          "second_arg",
          "--license-key",
          System.fetch_env!("SOME_LICENSE_KEY")
        ])
      end
    end

In the example above, we have defined three aliases. One is `mix c`
which is a shortcut for `mix compile`. Another is named
`mix hello` and the third is named `mix paid_task`, which executes
the code inside a custom function to invoke the `paid.task` task
with several arguments, including one pulled from an environment
variable.

Aliases may also be lists, specifying multiple tasks to be run
consecutively:

    [all: [&hello/1, "deps.get --only #{Mix.env()}", "compile"]]

In the example above, we have defined an alias named `mix all`,
that prints "Hello world", then fetches dependencies specific
to the current environment, and compiles the project.

Aliases can also be used to augment existing tasks. Let's suppose
you want to augment `mix clean` to clean another directory Mix does
not know about:

    [clean: ["clean", &clean_extra/1]]

Where `&clean_extra/1` would be a function in your `mix.exs`
with extra cleanup logic.

If the alias is overriding an existing task, the arguments given
to the alias will be forwarded to the original task in order to
preserve semantics. Otherwise arguments given to the alias are
appended to the arguments of the last task in the list.

Another use case of aliases is to run Elixir scripts and shell
commands, for example:

    # priv/hello1.exs
    IO.puts("Hello One")

    # priv/hello2.exs
    IO.puts("Hello Two")

    # priv/world.sh
    #!/bin/sh
    echo "world!"

    # mix.exs
    defp aliases do
      [
        some_alias: ["hex.info", "run priv/hello1.exs", "cmd priv/world.sh"]
      ]
    end

In the example above we have created the alias `some_alias` that will
run the task `mix hex.info`, then `mix run` to run an Elixir script,
then `mix cmd` to execute a command line shell script. This shows how
powerful aliases mixed with Mix tasks can be.

One common pitfall of aliases comes when trying to invoke the same task
multiple times. Mix tasks are designed to run only once. This prevents
the same task from being executed multiple times. For example, if there
are several tasks depending on `mix compile`, the code will be compiled
only once.

Similarly, `mix format` can only be invoked once. So if you have an alias
that attempts to invoke `mix format` multiple times, it won't work unless
it is explicitly reenabled using `Mix.Task.reenable/1`:

    another_alias: [
      "format --check-formatted priv/hello1.exs",
      "cmd priv/world.sh",
      fn _ -> Mix.Task.reenable("format") end,
      "format --check-formatted priv/hello2.exs"
    ]

Some tasks are automatically reenabled though, as they are expected to
be invoked multiple times, such as: `mix cmd`, `mix do`, `mix xref`, etc.

Finally, aliases defined in the current project do not affect its
dependencies and aliases defined in dependencies are not accessible
from the current project, with the exception of umbrella projects.
Umbrella projects will run the aliases of its children when the
umbrella project itself does not define said alias and there is no
task with said name.

## Environment variables

Several environment variables can be used to modify Mix's behavior.

Mix responds to the following variables:

  * `MIX_ARCHIVES` - specifies the directory into which the archives should be installed
    (default: `~/.mix/archives`)

  * `MIX_BUILD_PATH` - sets the project `Mix.Project.build_path/0`, including the
    current environment, such as "/path/to/project/_build/dev". This environment
    variable is used mostly by external build tools who need enforce a build
    directory independent of `MIX_ENV` and `MIX_TARGET`. For your CI servers,
    you likely want to use `MIX_BUILD_ROOT` below.

  * `MIX_BUILD_ROOT` - sets the root directory where build artifacts should be
    written to. For example, "/path/to/_build". If `MIX_BUILD_PATH` is set,
    this option is ignored.

  * `MIX_DEBUG` - outputs debug information about each task before running it

  * `MIX_DEPS_PATH` - sets the project `Mix.Project.deps_path/0` config for the
    current project, as an absolute path, such as `/path/to/project/deps`

  * `MIX_ENV` - specifies which environment should be used. See [Environments](#module-environments)

  * `MIX_EXS` - changes the full path to the `mix.exs` file

  * `MIX_HOME` - path to Mix's home directory, stores configuration files and scripts used by Mix
    (default: `~/.mix`)

  * `MIX_INSTALL_DIR` *(since v1.12.0)* - specifies directory where `Mix.install/2` keeps
     install cache

  * `MIX_OS_CONCURRENCY_LOCK` - when set to `0` or `false`, disables mix compilation locking.
    While not recommended, this may be necessary in cases where hard links or TCP sockets are
    not available. When opting for this behaviour, make sure to not start concurrent compilations
    of the same project

  * `MIX_OS_DEPS_COMPILE_PARTITION_COUNT` - when set to a number greater than 1, it enables
    compilation of dependencies over multiple operating system processes. See `mix help deps.compile`
    for more information

  * `MIX_PATH` - appends extra code paths

  * `MIX_PROFILE` - a list of comma-separated Mix tasks to profile the time spent on
    functions by the process running the task, such as `MIX_PROFILE=compile,test`.
    You can also set `MIX_PROFILE_FLAGS` to control the flags given to profiling,
    see `mix profile.tprof` for all options. By default, it uses `--no-warmup`.

  * `MIX_QUIET` - does not print information messages to the terminal

  * `MIX_REBAR3` - path to rebar3 command that overrides the one Mix installs
    (default: `~/.mix/rebar3`)

  * `MIX_TARGET` - specifies which target should be used. See [Targets](#module-targets)

  * `MIX_XDG` - asks Mix to follow the [XDG Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
    for its home directory and configuration files. This behavior needs to
    be opt-in due to backwards compatibility. `MIX_HOME` has higher preference
    than `MIX_XDG`. If none of the variables are set, the default directory
    `~/.mix` will be used

Environment variables that are not meant to hold a value (and act basically as
flags) should be set to either `1` or `true`, for example:

    $ MIX_DEBUG=1 mix compile

## SSL certificates

Mix and the Hex package manager use the default operating system certificates
when downloading resources. In certain situations, such as when running behind
proxies, you want to replace those certificates.

If you simply want to change the certificates used by Mix and Hex, you may set
the `HEX_CACERTS_PATH` environment variable, pointing to a CA certificate file.
See [`mix hex.config`](https://hex.hexdocs.pm/Mix.Tasks.Hex.Config.html#module-config-keys).

From Erlang/OTP 27.2, it is also possible to change the certificates for your
project as a whole. To do so, you might add the following to your `config/config.exs`:

    config :public_key, :cacerts_path, "/path/to/certs.pem"

You can also do so by setting the `ERL_AFLAGS` and `ERL_ZFLAGS` environment variables:

```bash
ERL_AFLAGS="-public_key cacerts_path '\"/path/to/certs.pem\"'"
ERL_ZFLAGS="-public_key cacerts_path '\"/path/to/certs.pem\"'"
```

You can verify if the configuration has been properly set by calling the following
inside `iex -S mix`:

    Application.load(:public_key)
    Application.get_env(:public_key, :cacerts_path)

And by loading the certificates:

    :public_key.cacerts_get()

# `install_opts`

```elixir
@type install_opts() :: [
  force: boolean(),
  verbose: boolean(),
  consolidate_protocols: boolean(),
  elixir: String.t(),
  system_env: Enum.t(),
  config: keyword(),
  config_path: String.t() | atom(),
  lockfile: String.t() | atom(),
  start_applications: boolean(),
  compilers: [atom()],
  runtime_config: keyword()
]
```

Options for `install/2`.

See the `install/2` function documentation for detailed information about each option.

# `compilers`

```elixir
@spec compilers() :: [atom()]
```

Returns the default compilers used by Mix.

It can be used in your `mix.exs` to prepend or
append new compilers to Mix:

    def project do
      [compilers: Mix.compilers() ++ [:foo, :bar]]
    end

# `debug`

```elixir
@spec debug(boolean()) :: :ok
```

Sets Mix debug mode.

# `debug?`

```elixir
@spec debug?() :: boolean()
```

Returns `true` if Mix is in debug mode, `false` otherwise.

# `ensure_application!`
*since 1.15.0* 

```elixir
@spec ensure_application!(Application.app()) :: :ok
```

Ensures the given application from Erlang/OTP or Elixir and its dependencies
are available in the path.

Generally speaking, you should list the Erlang application dependencies under
the `:extra_applications` section of your `mix.exs`. This must only be used by
Mix tasks which wish to avoid depending on Erlang/Elixir for certain reasons.

This function does not start the given applications.

# `env`

```elixir
@spec env() :: atom()
```

Returns the current Mix environment.

This function should not be used at runtime in application code (as opposed
to infrastructure and build code like Mix tasks). Mix is a build tool and may
not be available after the code is compiled (for example in a release).

To differentiate the program behavior depending on the environment, it is
recommended to use application environment through `Application.get_env/3`.
Proper configuration can be set in config files, often per-environment
(see the `Config` module for more information).

# `env`

```elixir
@spec env(atom()) :: :ok
```

Changes the current Mix environment to `env`.

Be careful when invoking this function as any project
configuration won't be reloaded.

This function should not be used at runtime in application code
(see `env/0` for more information).

# `install`
*since 1.12.0* 

```elixir
@spec install(
  [
    atom()
    | {atom(), String.t()}
    | {atom(), String.t(), keyword()}
    | {atom(), keyword()}
  ],
  install_opts()
) :: :ok
```

Installs and starts dependencies.

The given `deps` should be in the same format as defined in a regular Mix
project. See `mix help deps` for more information. As a shortcut, an atom
can be given as dependency to mean the latest version. In other words,
specifying `:decimal` is the same as `{:decimal, ">= 0.0.0"}`.

After each successful installation, a given set of dependencies is cached
so starting another VM and calling `Mix.install/2` with the same dependencies
will avoid unnecessary downloads and compilations. The location of the cache
directory can be controlled using the `MIX_INSTALL_DIR` environment variable.

This function can only be called outside of a Mix project and only with the
same dependencies in the given VM.

## Options

  * `:config` *(since v1.13.0)* - a keyword list of keyword lists of compile-time
    configuration. The configuration is part of the `Mix.install/2` cache, so
    different configurations will lead to different apps. For this reason, you
    want to minimize the amount of configuration set through this option.
    Use `Application.put_all_env/2` for setting other runtime configuration.

  * `:config_path` *(since v1.14.0)* - path to a configuration file. If a `runtime.exs`
    file exists in the same directory as the given path, it is loaded too.

  * `:consolidate_protocols` - if `true`, runs protocol consolidation (Default: `true`)

  * `:elixir` - if set, ensures the current Elixir version matches the given
    version requirement (Default: `nil`)

  * `:force` - if `true`, runs with empty install cache. This is useful when you want
    to update your dependencies or your install got into an inconsistent state.
    To use this option, you can also set the `MIX_INSTALL_FORCE` environment variable.
    (Default: `false`)

  * `:lockfile` *(since v1.14.0)* - path to a lockfile to be used as a basis of
    dependency resolution.

  * `:start_applications` *(since v1.15.3)* - if `true`, ensures that installed app
    and its dependencies are started after install (Default: `true`)

  * `:stop_unused_applications` *(since v1.20.0)* - as part of the installation process,
    Elixir may start Hex, SSL, and other applications. Those are automatically shutdown
    after installation, but you can set this option to false so they remain running

  * `:system_env` *(since v1.13.0)* - a list or a map of system environment variable
    names with respective values as binaries. The system environment is made part
    of the `Mix.install/2` cache, so different configurations will lead to different apps

  * `:verbose` - if `true`, prints additional debugging information
    (Default: `false`)

## Examples

Installing `:decimal` and `:jason`:

    Mix.install([
      :decimal,
      {:jason, "~> 1.0"}
    ])

Installing `:nx` and `:exla`, and configuring the underlying applications
and environment variables:

    Mix.install(
      [:nx, :exla],
      config: [
        nx: [default_backend: EXLA]
      ],
      system_env: [
        XLA_TARGET: "cuda111"
      ]
    )

Installing a Mix project as a path dependency along with its configuration
and deps:

    # $ git clone https://github.com/hexpm/hexpm /tmp/hexpm
    # $ cd /tmp/hexpm && mix setup

    Mix.install(
      [
        {:hexpm, path: "/tmp/hexpm", env: :dev},
      ],
      config_path: "/tmp/hexpm/config/config.exs",
      lockfile: "/tmp/hexpm/mix.lock"
    )

    Hexpm.Repo.query!("SELECT COUNT(1) from packages")
    #=> ...

The example above can be simplified by passing the application
name as an atom for `:config_path` and `:lockfile`:

    Mix.install(
      [
        {:hexpm, path: "/tmp/hexpm", env: :dev},
      ],
      config_path: :hexpm,
      lockfile: :hexpm
    )

## Limitations

There is one limitation to `Mix.install/2`, which is actually an Elixir
behavior. If you are installing a dependency that defines a struct or
macro, you cannot use the struct or macro immediately after the install
call. For example, this won't work:

    Mix.install([:decimal])
    %Decimal{} = Decimal.new(42)

That's because Elixir first expands all structs and all macros, and then
it executes the code. This means that, by the time Elixir tries to expand
the `%Decimal{}` struct, the dependency has not been installed yet.

Luckily this has a straightforward solution, which is to move the code
inside a module:

    Mix.install([:decimal])

    defmodule Script do
      def run do
        %Decimal{} = Decimal.new(42)
      end
    end

    Script.run()

The contents inside `defmodule` will only be expanded and executed
after `Mix.install/2` runs, which means that any struct, macros,
and imports will be correctly handled.

## Environment variables

The `MIX_INSTALL_DIR` environment variable configures the directory that
caches all `Mix.install/2`. It defaults to the `mix/install` folder in the
default user cache of your operating system. You can use `install_project_dir/0`
to access the directory of an existing install (alongside other installs):

    iex> Mix.install([])
    iex> Mix.install_project_dir()

The `MIX_INSTALL_FORCE` is available since Elixir v1.13.0 and forces
`Mix.install/2` to discard any previously cached entry of the current install.

The `MIX_INSTALL_RESTORE_PROJECT_DIR` environment variable may be specified
since Elixir v1.16.2. It should point to a previous installation directory,
which can be obtained with `Mix.install_project_dir/0` (after calling `Mix.install/2`).
Using a restore dir may speed up the installation, since matching dependencies
do not need be refetched nor recompiled. This environment variable is ignored
if `:force` is enabled.

# `install_project_dir`
*since 1.16.2* 

```elixir
@spec install_project_dir() :: Path.t() | nil
```

Returns the directory where the current `Mix.install/2` project
resides.

# `installed?`
*since 1.13.0* 

```elixir
@spec installed?() :: boolean()
```

Returns whether `Mix.install/2` was called in the current node.

# `path_for`
*since 1.10.0* 

```elixir
@spec path_for(:archives | :escripts) :: String.t()
```

The path for local archives or escripts.

# `raise`

```elixir
@spec raise(binary()) :: no_return()
```

Raises a Mix error that is nicely formatted, defaulting to exit status `1`.

# `raise`
*since 1.12.3* 

```elixir
@spec raise(binary(), [{:exit_status, non_neg_integer()}]) :: no_return()
```

Raises a Mix error that is nicely formatted.

## Options

  * `:exit_status` - defines exit status, defaults to `1`

# `shell`

```elixir
@spec shell() :: module()
```

Returns the current shell.

`shell/0` can be used as a wrapper for the current shell. It contains
conveniences for requesting information from the user, printing to the
shell and so forth. The Mix shell is swappable (see `shell/1`), allowing
developers to use a test shell that simply sends messages to the current
process instead of performing IO (see `Mix.Shell.Process`).

By default, this returns `Mix.Shell.IO`.

## Examples

    Mix.shell().info("Preparing to do something dangerous...")

    if Mix.shell().yes?("Are you sure?") do
      # do something dangerous
    end

# `shell`

```elixir
@spec shell(module()) :: :ok
```

Sets the current shell.

As an argument you may pass `Mix.Shell.IO`, `Mix.Shell.Process`,
`Mix.Shell.Quiet`, or any module that implements the `Mix.Shell`
behaviour.

After calling this function, `shell` becomes the shell that is
returned by `shell/0`.

## Examples

    iex> Mix.shell(Mix.Shell.IO)
    :ok

You can use `shell/0` and `shell/1` to temporarily switch shells,
for example, if you want to run a Mix Task that normally produces
a lot of output:

    shell = Mix.shell()
    Mix.shell(Mix.Shell.Quiet)

    try do
      Mix.Task.run("noisy.task")
    after
      Mix.shell(shell)
    end

# `target`

```elixir
@spec target() :: atom()
```

Returns the Mix target.

# `target`

```elixir
@spec target(atom()) :: :ok
```

Changes the current Mix target to `target`.

Be careful when invoking this function as any project
configuration won't be reloaded.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
