# Elixir v1.10.3 Config.Provider behaviour View Source

Specifies a provider API that loads configuration during boot.

Config providers are typically used during releases to load external configuration while the system boots. This is done by starting the VM with the minimum amount of applications running, then invoking all of the providers, and then restarting the system. This requires a mutable configuration file on disk, as the results of the providers are written to the file system. For more information on runtime configuration, see `mix release`.

## Sample config provider

For example, imagine you need to load some configuration from a JSON file and load that into the system. Said configuration provider would look like:

    defmodule JSONConfigProvider do
      @behaviour Config.Provider

      # Let's pass the path to the JSON file as config
      def init(path) when is_binary(path), do: path

      def load(config, path) do
        # We need to start any app we may depend on.
        {:ok, _} = Application.ensure_all_started(:jason)

        json = path |> File.read!() |> Jason.decode!()

        Config.Reader.merge(
          config,
          my_app: [
            some_value: json["my_app_some_value"],
            another_value: json["my_app_another_value"],
          ]
        )
      end
    end

Then when specifying your release, you can specify the provider in the release configuration:

    releases: [
      demo: [
        # ...,
        config_providers: [{JSONConfigProvider, "/etc/config.json"}]
      ]
    ]

Now once the system boots, it will invoke the provider early in the boot process, save the merged configuration to the disk, and reboot the system with the new values in place.

# Link to this section Summary

## Types

config()
config_path()

A path pointing to a configuration file.

state()

## Functions

resolve_config_path!(path)

Resolves a `t:config_path/0` to an actual path.

validate_config_path!(path)

Validates a `t:config_path/0`.

## Callbacks

init(term)

Invoked when initializing a config provider.

load(config, state)

Loads configuration (typically during system boot).

# Link to this section Types

Link to this type

# config()

View Source

## Specs

    config() :: keyword()

Link to this type

# config_path()

View Source

## Specs

    config_path() :: {:system, binary(), binary()} | binary()

A path pointing to a configuration file.

Since configuration files are often accessed on target machines, it can be expressed either as:

- a binary representing an absolute path

- a `{:system, system_var, path}` tuple where the config is the concatenation of the environment variable `system_var` with the given `path`

Link to this type

# state()

View Source

## Specs

    state() :: term()

# Link to this section Functions

Link to this function

# resolve_config_path!(path)

View Source (since 1.9.0)

## Specs

    resolve_config_path!(config_path()) :: binary()

Resolves a `t:config_path/0` to an actual path.

Link to this function

# validate_config_path!(path)

View Source (since 1.9.0)

## Specs

    validate_config_path!(config_path()) :: :ok

Validates a `t:config_path/0`.

# Link to this section Callbacks

Link to this callback

# init(term)

View Source

## Specs

    init(term()) :: state()

Invoked when initializing a config provider.

A config provider is typically initialized on the machine where the system is assembled and not on the target machine. The `c:init/1` callback is useful to verify the arguments given to the provider and prepare the state that will be given to `c:load/2`.

Furthermore, because the state returned by `c:init/1` can be written to text-based config files, it should be restricted only to simple data types, such as integers, strings, atoms, tuples, maps, and lists. Entries such as PIDs, references, and functions cannot be serialized.

Link to this callback

# load(config, state)

View Source

## Specs

    load(config(), state()) :: config()

Loads configuration (typically during system boot).

It receives the current `config` and the `state` returned by `c:init/1`. Then you typically read the extra configuration from an external source and merge it into the received `config`. Merging should be done with `Config.Reader.merge/2`, as it performs deep merge. It should return the updated config.

Note that `c:load/2` is typically invoked very early in the boot process, therefore if you need to use an application in the provider, it is your responsibility to start it.