Personal Phoenix 1.6 Upgrade Notes

Over the past few days I’ve been upgrading my projects to Phoenix 1.6 and like any project that comes out of a template-based generator, migrating a Phoenix project to a new version can be a little scary and error prone, particularly for people new to Elixir and Phoenix. Today I’ll share some personal notes and tips to hopefully make the process a little smoother.

Step 0: Skip the Manual Upgrade (Maybe?)

Depending on the scale and circumstances of your project you might consider just re-generating a new project using mix and bringing over your old code into the fresh template. I wouldn’t recommend this for any project that had meaningful git history or other collaborators, but for smaller personal projects it might be the path of least resistance.

You’ll probably want the new project generator regardless and can install it with:

$ mix archive.install hex phx_new

Step 1: Familiarize Yourself with the New Version

Before blindly attempting the upgrade it would be best to read the official blog announcement, review the project changelog and preview Chris McCord’s personal upgrade notes. You might want to also bookmark documentation for specific new features, like heex templates.

Step 2: Get Your Project is a Stable State

Make sure your project is building clean, the tests are passing and the typespecs are um, type spec-ing. Push your changes to remote and start a new upgrade-phoenix branch. It would be best if you work through the upgrade in chunks and verify these things as you go.

Step 3: Update Elixir and Project Dependencies

If you can, now is a good time to explicitly require Elixir 1.12 as the minimum version of your project. This is not an absolute requirement, but as described in the heex docs, it will improve your error messages:

Note: HEEx requires Elixir >= 1.12.0 in order to provide accurate file:line:column information in error messages. Earlier Elixir versions will work but will show inaccurate error messages.

  # mix.exs
  def project do
      # ...
      elixir: "~> 1.12",

If you are using an asdf for version management you might also want to update your .tool-versions file as well.

Next run mix hex.outdated to see what dependency updates are available. You’ll see a bunch of stuff for the new Phoenix 1.6 release, which at the time of this post is up to 1.6.2. For one of our currently outdated projects I get the following:

$ mix hex.outdated
Dependency              Current  Latest   Status               
credo                   1.5.6    1.5.6    Up-to-date           
dialyxir                1.1.0    1.1.0    Up-to-date           
ecto_sql                3.6.2    3.7.1    Update possible      
floki                   0.29.0   0.31.0   Update not possible  
gettext                 0.18.2   0.18.2   Up-to-date           
jason                   1.2.2    1.2.2    Up-to-date           
mix_test_watch          1.0.3    1.1.0    Update possible      
phoenix                 1.5.9    1.6.2    Update not possible  
phoenix_ecto            4.3.0    4.4.0    Update possible      
phoenix_html            2.14.3   3.0.4    Update not possible  
phoenix_live_dashboard  0.4.0    0.5.3    Update possible      
phoenix_live_reload     1.3.3    1.3.3    Up-to-date           
plug_cowboy             2.5.1    2.5.2    Update possible      
postgrex                0.15.10  0.15.12  Update possible      
telemetry_metrics       0.6.1    0.6.1    Up-to-date           
telemetry_poller        0.5.1    1.0.0    Update not possible

Using the above collection of versions you can update your mix.exs deps list. To verify these work try running the following commands in series:

Fix any issues that popup and then you can commit your progress and start to consider some of the optional parts of the 1.6 upgrade.

Step 4: Migrate to heex Templates (optional)

The new template system is called heex (pronounced heaks) and is more HTML-aware, helping report issues like missing div tags at compile time. The new heex templates will help resolve a notable collection of common LiveView and CSS bugs as well as provide nicer inline functions.

While heex templates are great they are optional for now. Previous eex and leex templates still work but are considered deprecated. If you want to start to migrate to heex I would check out the docs for a quick overview and then start renaming your file extensions like:

For inline templates you’ll use the new ~H sigil instead of ~L sigil.

As you make these changes the compiler will inform you what needs updating. For my own RetroTaxi project most heex updates involved migrating HTML attributes like:

- <div id="topic-card-<%= %>">
+ <div id={"topic-card#{}"}>


- <button phx-click="start_discussion_phase" phx-target="<%= @myself %>"
+ <button phx-click="start_discussion_phase" phx-target={@myself}

I also ended up using the new <.form> component, which honors the tag aware templates while also addressing a known technical limitation of live_components being wrapped in a block, which is a common pattern inside forms.

- <%= f = form_for @changeset, "#", phx_submit: "save", phx_target: @myself %>
- <!-- stuff -->
- </form>
+ <.form let={f} for={@changeset} phx_submit={"save"} phx_target={@myself}>
+ <!-- stuff -->
+ </.form>

Step 5: Migrate to esbuild (optional)

With Phoenix 1.6 all new project templates will default to esbuild over the historic webpack for asset bundling. This was a change made in an effort to improve long term stability, as npm and webpack have been a huge source of bugs and maintenance issues inside the Phoenix project. This is however an optional change when upgrading older Phoenix projects.

If you already have invested in any webpack customizations you might just want to keep using it.

If your needs are simple and you’d like to give esbuild a spin it can be swapped in without too much work. Chris McCord’s upgrade document has an in-depth set of edits you can follow. I did those steps myself with RetroTaxi and then once I got it all working, went back and re-added my Tailwind dependencies following Mike Clark’s blog post. I ended up with a very basic package.json file.

Aside: One notable question I still have regarding esbuild is the new command: mix assets.deploy. It seems curious to me that running this with the new .gitignore patterns results in a dirty git state. Is this wanted/expected behavior? If you have any thoughts let me know.

Step 6: The Little Things

There are lots of little things you can notice comparing your current Phoenix 1.5 project with a freshly generated 1.6 project. In fact I recommend using mix hello (substituting your own project name for hello to help with easier copy and paste) and then compare the new project files 1:1 against your current project. You’ll no doubt notice things like:

For RetroTaxi I tried to honor these changes as much as possible.

One helpful tool to do this kind of template comparison at a glace is PhoenixDiffs:

My Final Upgrade PR and Next Steps

The final RetroTaxi Phoenix 1.6 upgrade PR is here if you want to take a peek:

One new feature I have my eye on but did not get around too (yet) is Phoenix.Component. I should be able to use this in favor of some historic stateless LiveComponent modules, which is no longer recommended, as seen in the docs quoted below:

Note: previous LiveView versions allowed the :id to be skipped on live_component but those are now discouraged since the addition of function components, outlined in Phoenix.Component.

Hopefully these notes provide some help and comfort as you upgrade your own Phoenix projects to 1.6. I’m curious how we can continue to improve this process in the future and even have my eye on some new Elixir 1.13 changes that could help by “supporting developers who wish to create tools that directly manipulate and custom format Elixir source code”.

Thanks again to the entire Phoenix team for an outstanding release!