The usage of contexts is a major new concept introduced in Phoenix 1.3 which helps us to write more maintainable and reusable code. The idea of a context is very simple, but this new way of structuring your application will significantly improve your overall architecture.

A context is basically an Elixir module which groups related functions to provide a consistent API which can be used by other parts of your application. A context module is placed within a context directory with the same name as the corresponding module as shown below.

  • lib
    • my_app
      • accounts # Context Directory
        • accounts.ex # Context Module
        • role.ex
        • user.ex

In Phoenix 1.3 we need to specify the name of a context when creating a new html/json resource. The following command to generate a new resource will create the context directory named accounts first and place all the User related functions like get_user!, create_user etc within the context module MyApp.Accounts (accounts.ex).

mix phx.gen.html Accounts User users email:string:unique
defmodule MyApp.Accounts do
  @moduledoc """
  The Accounts context.
  lib\my_app\accounts\accounts.ex
  """
  # ....
  def get_user!(id), do: Repo.get!(User, id)
  # ....
end

If you take a look at lib\my_app_web\controllers\user_controller.ex you can see how these context module functions are invoked from the various controller actions.

defmodule MyAppWeb.UserController do
  # ....
  def show(conn, %{"id" => id}) do
    user = Accounts.get_user!(id)
    render(conn, "show.html", user: user)
  end
  # ....
end

You can call these context module functions from any other part of your application like channels, test cases, mix tasks etc and also from other context modules. For example, to get a user by an id, you can just call Accounts.get_user!(id) which is more meaningful than fetching the data directly through Repo. Just like these basic CRUD functions, you can define your other complex business logic functions in appropriate context modules so as to facilitate reusability and testability.

A new context directory and context module are only created the first time when you generate a resource belonging to that context. The next time when you generate a new resource within the same context, the functions of the new resource will be appended to the already existing context module. For example executing mix phx.gen.html Accounts Role roles name:string will append the definitions of functions like get_role!, create_role etc to MyApp.Accounts since we already have the accounts context.

As you may have already noticed , the Ecto schemas of all modules within a context are also placed within that context directory. By just having a look at the above directory structure, we can understand that the modules role and user are within the same context named accounts. Having such an insight into the structure your application will contribute a lot to the maintainability.