     end
   end
 
-  defp load_app(app, validate_compile_env?) do
+  defp load_app(app, deps, lib_path, validate_compile_env?) do
     if Application.spec(app, :vsn) do
       :ok
     else
-      name = Atom.to_charlist(app) ++ '.app'
-
-      with [_ | _] = path <- :code.where_is_file(name),
-           {:ok, {:application, _, properties} = application_data} <- consult_app_file(path),
+      with {:ok, bin} <- read_app(app, deps, lib_path),
+           {:ok, {:application, _, properties} = application_data} <- consult_app_file(bin),
            :ok <- :application.load(application_data) do
         if compile_env = validate_compile_env? && properties[:compile_env] do
           Config.Provider.validate_compile_env(compile_env, false)

    end
  end

  defp consult_app_file(path) do
    # The path could be located in an .ez archive, so we use the prim loader.
    with {:ok, bin, _full_name} <- :erl_prim_loader.get_file(path),
         {:ok, tokens, _} <- :erl_scan.string(String.to_charlist(bin)) do
      :erl_parse.parse_term(tokens)
    end
  end


  ## App loading helpers

  defp load_apps(config, lib_path, validate_compile_env?) do
    {runtime, optional} = Mix.Tasks.Compile.App.project_apps(config)
    parent = self()
    opts = [ordered: false, timeout: :infinity]
    deps = for dep <- Mix.Dep.cached(), into: %{}, do: {dep.app, true}

    stream_apps(runtime ++ optional)
    |> Task.async_stream(&load_app(&1, parent, deps, lib_path, validate_compile_env?), opts)
    |> Stream.run()
  end

  defp load_app(app, parent, deps, lib_path, validate_compile_env?) do
    children =
      case load_app(app, deps, lib_path, validate_compile_env?) do
        :ok ->
          Application.spec(app, :applications) ++ Application.spec(app, :included_applications)

