View Source Mix.Project (Mix v1.18.0-dev)

Defines and manipulates Mix projects.

A Mix project is defined by calling use Mix.Project in a module, usually placed in mix.exs:

defmodule MyApp.MixProject do
  use Mix.Project

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

use Mix.Project

When you use Mix.Project, it notifies Mix that a new project has been defined, so all Mix tasks use your module as a starting point.

Configuration

In order to configure Mix, the module that calls use Mix.Project should export a project/0 function that returns a keyword list representing configuration for the project.

This configuration can be read using Mix.Project.config/0. Note that config/0 won't fail if a project is not defined; this allows many Mix tasks to work without a project.

If a task requires a project to be defined or needs to access a special function within the project, the task can call Mix.Project.get!/0 which fails with Mix.NoProjectError in the case a project is not defined.

There isn't a comprehensive list of all the options that can be returned by project/0 since many Mix tasks define their own options that they read from this configuration. For example, look at the "Configuration" section in the documentation for the Mix.Tasks.Compile task.

These are a few options that are not used by just one Mix task (and will thus be documented here):

  • :build_per_environment - if true, builds will be per-environment. If false, builds will go in _build/shared regardless of the Mix environment. Defaults to true.

  • :aliases - a list of task aliases. For more information, check out the "Aliases" section in the documentation for the Mix module. Defaults to [].

  • :config_path - a string representing the path of the main config file. See config_files/0 for more information. Defaults to "config/config.exs".

  • :deps - a list of dependencies of this project. Refer to the documentation for the Mix.Tasks.Deps task for more information. Defaults to [].

  • :deps_path - directory where dependencies are stored. Also see deps_path/1. Defaults to "deps".

  • :lockfile - the name of the lockfile used by the mix deps.* family of tasks. Defaults to "mix.lock".

Mix tasks may require their own configuration inside def project. For example, check the Mix.Tasks.Compile task and all the specific compiler tasks (such as Mix.Tasks.Compile.Elixir or Mix.Tasks.Compile.Erlang).

Note that different tasks may share the same configuration option. For example, the :erlc_paths configuration is used by mix compile.erlang, mix compile.yecc, and other tasks.

CLI configuration

Mix is most often invoked from the command line. For this purpose, you may define a specific cli/0 function which customizes default values when executed from the CLI. For example:

def cli do
  [
    default_task: "phx.server",
    preferred_envs: [docs: :docs]
  ]
end

The example above sets the default task (used by iex -S mix and mix) to phx.server. It also sets the default environment for the "mix docs" task to be "docs".

The following CLI configuration are available:

  • :default_env - the default environment to use when none is given and MIX_ENV is not set

  • :default_target - the default target to use when none is given and MIX_TARGET is not set

  • :default_task - the default task to invoke when none is given

  • :preferred_envs - a keyword list of {task, env} tuples where task is the task name as an atom (for example, :"deps.get") and env is the preferred environment (for example, :test)

  • :preferred_targets - a keyword list of {task, target} tuples where task is the task name as an atom (for example, :test) and target is the preferred target (for example, :host)

Erlang projects

Mix can be used to manage Erlang projects that don't have any Elixir code. To ensure Mix tasks work correctly for an Erlang project, language: :erlang has to be part of the configuration returned by project/0. This setting also makes sure Elixir is not added as a dependency to the generated .app file or to the escript generated with mix escript.build, and so on.

Invoking this module

This module contains many functions that return project information and metadata. However, since Mix is not included nor configured during releases, we recommend using the functions in this module only inside Mix tasks. If you need to configure your own app, consider using the application environment instead. For example, don't do this:

def some_config do
  Mix.Project.config()[:some_config]
end

Nor this:

@some_config Mix.Project.config()[:some_config]

Instead, do this:

def some_config do
  Application.get_env(:my_app, :some_config)
end

Or this:

@some_config Application.compile_env(:my_app, :some_config)

Summary

Functions

Returns the application path inside the build.

Returns a map with the umbrella child applications paths.

Returns the build path for the given project.

Builds the project structure for the given application.

Clears the dependency for the current environment.

Returns the paths the given project compiles to.

Returns the project configuration.

Returns a list of project configuration files for this project.

Returns the latest modification time from config files.

Returns the path where protocol consolidations are stored.

Returns all dependencies app names.

Returns the path where dependencies are stored for the given project.

Returns the full path of all dependencies as a map.

Returns the SCMs of all dependencies as a map.

Returns the dependencies of all dependencies as a map.

Ensures the project structure for the given project exists.

Retrieves the current project if there is one.

Same as get/0, but raises an exception if there is no current project.

Runs the given fun inside the given project.

Returns the path where manifests are stored.

Returns the path to the file that defines the parent umbrella project, if one.

Returns the path to the file that defines the current project.

Returns true if config is the configuration for an umbrella project.

Functions

app_path(config \\ config())

@spec app_path(keyword()) :: Path.t()

Returns the application path inside the build.

The returned path will be expanded.

Examples

If your project defines the app my_app:

Mix.Project.app_path()
#=> "/path/to/project/_build/shared/lib/my_app"

apps_paths(config \\ config())

(since 1.4.0)
@spec apps_paths(keyword()) :: %{optional(atom()) => Path.t()} | nil

Returns a map with the umbrella child applications paths.

These paths are based on the :apps_path and :apps configurations.

If the given project configuration identifies an umbrella project, the return value is a map of app => path where app is a child app of the umbrella and path is its path relative to the root of the umbrella project.

If the given project configuration does not identify an umbrella project, nil is returned.

Examples

Mix.Project.apps_paths()
#=> %{my_app1: "apps/my_app1", my_app2: "apps/my_app2"}

build_path(config \\ config())

@spec build_path(keyword()) :: Path.t()

Returns the build path for the given project.

The build path is built based on the :build_path configuration (which defaults to "_build") and a subdirectory. The subdirectory is built based on two factors:

  • If :build_per_environment is set, the subdirectory is the value of Mix.env/0 (which can be set via MIX_ENV). Otherwise it is set to "shared".

  • If Mix.target/0 is set (often via the MIX_TARGET environment variable), it will be used as a prefix to the subdirectory.

Finally, the environment variables MIX_BUILD_ROOT and MIX_BUILD_PATH can be used to change the result of this function. MIX_BUILD_ROOT overwrites only the root "_build" directory while keeping the subdirectory as is. It may be useful to change it for caching reasons, typically during Continuous Integration (CI). MIX_BUILD_PATH overrides the build path altogether and it typically used by other build tools that invoke the mix CLI.

Naming differences

Ideally the configuration option :build_path would be called :build_root, as it would fully mirror the environment variable. However, its name is preserved for backwards compatibility.

Examples

Mix.Project.build_path()
#=> "/path/to/project/_build/shared"

If :build_per_environment is set to true, it will create a new build per environment:

Mix.env()
#=> :dev
Mix.Project.build_path()
#=> "/path/to/project/_build/dev"

build_structure(config \\ config(), opts \\ [])

@spec build_structure(keyword(), keyword()) :: :ok

Builds the project structure for the given application.

Options

  • :symlink_ebin - symlink ebin instead of copying it

clear_deps_cache()

(since 1.7.0)
@spec clear_deps_cache() :: :ok

Clears the dependency for the current environment.

Useful when dependencies need to be reloaded due to change of global state.

For example, Nerves uses this function to force all dependencies to be reloaded after it updates the system environment. It goes roughly like this:

  1. Nerves fetches all dependencies and looks for the system specific deps
  2. Once the system specific dep is found, it loads it alongside env vars
  3. Nerves then clears the cache, forcing dependencies to be loaded again
  4. Dependencies are loaded again, now with an updated env environment

compile_path(config \\ config())

@spec compile_path(keyword()) :: Path.t()

Returns the paths the given project compiles to.

If no configuration is given, the one for the current project will be used.

The returned path will be expanded.

Examples

If your project defines the app my_app:

Mix.Project.compile_path()
#=> "/path/to/project/_build/dev/lib/my_app/ebin"

config()

@spec config() :: keyword()

Returns the project configuration.

If there is no project defined, it still returns a keyword list with default values. This allows many Mix tasks to work without the need for an underlying project.

Note this configuration is cached once the project is pushed onto the stack. Calling it multiple times won't cause it to be recomputed.

Do not use Mix.Project.config/0 to find the runtime configuration. Use it only to configure aspects of your project (like compilation directories) and not your application runtime.

config_files()

@spec config_files() :: [Path.t()]

Returns a list of project configuration files for this project.

This function is usually used in compilation tasks to trigger a full recompilation whenever such configuration files change.

It returns the lock manifest, and all config files in the config directory that do not start with a leading period (for example, .my_config.exs).

Note: before Elixir v1.13.0, the mix.exs file was also included as a config file, but since then it has been moved to its own function called project_file/0.

config_mtime()

(since 1.7.0)
@spec config_mtime() :: posix_mtime when posix_mtime: integer()

Returns the latest modification time from config files.

This function is usually used in compilation tasks to trigger a full recompilation whenever such configuration files change. For this reason, the mtime is cached to avoid file system lookups.

However, for effective used of this function, you must avoid comparing source files with the config_mtime itself. Instead, store the previous config_mtime and compare it with the new config_mtime in order to detect if something is stale.

Note: before Elixir v1.13.0, the mix.exs file was also included in the mtimes, but not anymore. You can compute its modification date by calling project_file/0.

consolidation_path(config \\ config())

@spec consolidation_path(keyword()) :: Path.t()

Returns the path where protocol consolidations are stored.

The returned path will be expanded.

Examples

If your project defines the app my_app:

Mix.Project.consolidation_path()
#=> "/path/to/project/_build/dev/lib/my_app/consolidated"

Inside umbrellas:

Mix.Project.consolidation_path()
#=> "/path/to/project/_build/dev/consolidated"

deps_apps()

(since 1.11.0)
@spec deps_apps() :: [atom()]

Returns all dependencies app names.

The order they are returned is guaranteed to be sorted for proper dependency resolution. For example, if A depends on B, then B will listed before A.

deps_path(config \\ config())

@spec deps_path(keyword()) :: Path.t()

Returns the path where dependencies are stored for the given project.

If no configuration is given, the one for the current project is used.

The returned path will be expanded.

Examples

Mix.Project.deps_path()
#=> "/path/to/project/deps"

deps_paths(opts \\ [])

@spec deps_paths(keyword()) :: %{optional(atom()) => Path.t()}

Returns the full path of all dependencies as a map.

Options

  • :depth - only returns dependencies to the depth level, a depth of 1 will only return top-level dependencies
  • :parents - starts the dependency traversal from the given parents instead of the application root

Examples

Mix.Project.deps_paths()
#=> %{foo: "deps/foo", bar: "custom/path/dep"}

deps_scms(opts \\ [])

(since 1.10.0)
@spec deps_scms(keyword()) :: %{optional(atom()) => Mix.SCM.t()}

Returns the SCMs of all dependencies as a map.

See Mix.SCM module documentation to learn more about SCMs.

Options

  • :depth - only returns dependencies to the depth level, a depth of 1 will only return top-level dependencies
  • :parents - starts the dependency traversal from the given parents instead of the application root

Examples

Mix.Project.deps_scms()
#=> %{foo: Mix.SCM.Path, bar: Mix.SCM.Git}

deps_tree(opts \\ [])

(since 1.15.0)
@spec deps_tree(keyword()) :: %{optional(atom()) => [atom()]}

Returns the dependencies of all dependencies as a map.

Options

  • :depth - only returns dependencies to the depth level, a depth of 1 will only return top-level dependencies
  • :parents - starts the dependency traversal from the given parents instead of the application root

Examples

Mix.Project.deps_tree()
#=> %{foo: [:bar, :baz], bar: [], baz: []}

ensure_structure(config \\ config(), opts \\ [])

@spec ensure_structure(keyword(), keyword()) :: :ok

Ensures the project structure for the given project exists.

In case it does exist, it is a no-op. Otherwise, it is built.

opts are the same options that can be passed to build_structure/2.

get()

@spec get() :: module() | nil

Retrieves the current project if there is one.

If there is no current project, nil is returned. This may happen in cases there is no mix.exs in the current directory.

If you expect a project to be defined, i.e., it is a requirement of the current task, you should call get!/0 instead.

get!()

@spec get!() :: module()

Same as get/0, but raises an exception if there is no current project.

This is usually called by tasks that need additional functions on the project to be defined. Since such tasks usually depend on a project being defined, this function raises a Mix.NoProjectError exception in case no project is available.

in_project(app, path, post_config \\ [], fun)

@spec in_project(atom(), Path.t(), keyword(), (module() -> result)) :: result
when result: term()

Runs the given fun inside the given project.

This function changes the current working directory and loads the project at the given directory onto the project stack.

A post_config can be passed that will be merged into the project configuration.

fun is called with the module name of the given Mix.Project. The return value of this function is the return value of fun.

Examples

Mix.Project.in_project(:my_app, "/path/to/my_app", fn module ->
  "Mix project is: #{inspect(module)}"
end)
#=> "Mix project is: MyApp.MixProject"

load_paths(config \\ config())

This function is deprecated. Use Mix.Project.compile_path/1 instead.

manifest_path(config \\ config())

@spec manifest_path(keyword()) :: Path.t()

Returns the path where manifests are stored.

By default they are stored in the app path inside the build directory. Umbrella applications have the manifest path set to the root of the build directory. Directories may be changed in future releases.

The returned path will be expanded.

Examples

If your project defines the app my_app:

Mix.Project.manifest_path()
#=> "/path/to/project/_build/shared/lib/my_app/.mix"

parent_umbrella_project_file()

(since 1.15.0)
@spec parent_umbrella_project_file() :: binary() | nil

Returns the path to the file that defines the parent umbrella project, if one.

The majority of the time, it will point to a mix.exs file. Returns nil if not inside a project or not inside an umbrella.

project_file()

(since 1.13.0)
@spec project_file() :: binary() | nil

Returns the path to the file that defines the current project.

The majority of the time, it will point to a mix.exs file. Returns nil if not inside a project.

umbrella?(config \\ config())

@spec umbrella?(keyword()) :: boolean()

Returns true if config is the configuration for an umbrella project.

When called with no arguments, tells whether the current project is an umbrella project.