Normally in MVC frameworks, the view and the template are essentially the same thing. But in the case of Phoenix Framework, they refer to different components. This distinction often confuses developers coming from other frameworks.

In the Phoenix world, templates are files that usually contain the HTML markup and some dynamic Elixir code. We write templates with Embedded Elxir (EEx) and they are stored with the extension .html.eex inside web/templates. When we generate a new Phoenix application, the template for the home page will be at web/templates/page/index.html.eex.

If you open up the controller at web/controllers/page_controller.ex you can see the call to render this template

def index(conn, _params) do
  render conn, "index.html"

Actually, this is indirectly calling a render function defined in the PageView module at web/views/page_view.ex. When you open that file you can see no such function definition. But if you enter MyApp.PageView.render("index.html",%{}) inside the iex shell running the app, you can see the contents of the template file. The magic is happening here. Phoenix takes web/templates/page/index.html.eex, compiles it to Elixir code and add it as a function in the PageView module as shown below

def render("index.html",_assigns) do
  "Compiled EEx template"

If you copy the above code and paste that in web/views/page_view.ex, you can notice that it is overriding the compiled template function.

In conclusion, Phoenix templates are compiled to rendering functions and are placed in the corresponding view modules. This pre-compilation of templates is one of the reasons for its blazing speed. In addition to the rendering functions, we can define other helper functions in the view module which can be called from the templates for transforming the data before presentation.