Tutorial

Step by step guide to deploy Phoenix 1.6 with LiveView and Tailwind on Render

deployrenderliveview

Sooner or later there comes a time when you want to deploy your Phoenix application. Render is a great PAAS service that offer easy deplyment for a great value. I have prepared both the Phoenix Boilerplate and the SAAS Starter Kit to make this deplyment as easy as possible. This also works with Phoenix LiveView and Esbuild as well as Tailwind.

They already have a deply guide on their docs section but it is for an older version of Phoenix and it doesnt use Ecto and Postgres.

Step 1 - Prepare your Phoenix app

As I mentioned above, I have already made some legwork and included almost all of the changes needed in the boilerplates and the SAAS Starter Kit. However, if you have not used it, here we go.

In the root of my app, I need to create a build file. Render will use this file when doing the deploy.

#!/usr/bin/env bash
# exit on error
set -o errexit

# Initial setup
mix deps.get --only prod
MIX_ENV=prod mix compile
MIX_ENV=prod mix assets.deploy

# Build the release and overwrite the existing release directory
MIX_ENV=prod mix release --overwrite

# Run migrations
_build/prod/rel/tutorial/bin/tutorial eval "Release.migrate"

NOTE - Replace tutorial with your app name.

I need to make the script is executable to be able to run it:

chmod a+x build.sh

Also, as you can see above in the script, there is a function call here. Release.migrate . This module takes care on running the migrations on every deploy. That module looks like this:

# lib/release.ex
defmodule Release do
  @app :tutorial

  def migrate do
    load_app()

    for repo <- repos() do
      {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
    end
  end

  def rollback(repo, version) do
    load_app()
    {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
  end

  defp repos do
    Application.fetch_env!(@app, :ecto_repos)
  end

  defp load_app do
    Application.load(@app)
  end
end

NOTE - once again, change :tutorial to your app name.

I need to set the release to be a standalone server. For that I need to uncomment the row:

# config/runtime.exs
# Make sure to uncomment
config :tutorial, TutorialWeb.Endpoint, server: true 

Next step is to change prod config so I can connect with another domain than example.com and dont have to buy that one. For that I need to change the line url: [host: "example.com", port: 80],

#  config/prod.exs
url: [host: System.get_env("RENDER_EXTERNAL_HOSTNAME") || "localhost", port: 80],

RENDER_EXTERNAL_HOSTNAME is the temporary url used for testing. When you are ready to point your domain to Render, update this with your domain name. But for now, this will do.

Next step is about when you dont have Mix available at runtime. So code like.

# Does not work
Mix.env() == :test

# Does work
Application.get_env(:tutorial, :env)

So, to make this work, I need to add this in the config.

# config/config.exs
config :tutorial, :env, Mix.env()

This is needed to be changes in the routes file where the mailbox route is. The mailbox is only visible in dev environment. So, same for live dashboard if you dont want that in production. So, change that is the routes file:

# lib/tutorial_web/router.ex
Application.get_env(:tutorial, :env) == :dev

Ok, that should be the changes needed. If I dont already have a Github repo, I need to do that and push these changes.

Step 2 - Create a Render app

The obvious first substep here is to create a Render account.

For simplicity, sign in with GitHub or if you are using GitLab. I will need that integration later to let Render get access to an eventual private repository that I will deploy. With this done, and maybe add a credit card, I can now create the app.

Create database

Since my app needs to have a database created to deploy, it make sense to create the database first. And currently, you can start with a database for as low as $7 per month.

The name of the database should be my_app_prod for convention. Then I have the option to pick region and version of the database and leave the rest as it is.

After the database is created I can copy the internal connection url. I will need that to use as an ENV variable for the phoenix app.

Create Phoenix app

Create a new webservice from the menu in the top. Render wont have access to my repos by default, so I first need to click the connect link to through GitHub give access to one or more repos.

When that is done, and I have picked it, I can name and setup the app. The starter plan here is also $7 per month. The important things here are to get the build and start commands

# Build command
./build.sh
# Start command
_build/prod/rel/tutorial/bin/tutorial start

Next important part are to set the ENV variables here as well. They are in the bottom of the page under advanced. The ones I need to set might depend on my application but at least

SECRET_KEY_BASE= # run phx.gen.secret in your console
DATABASE_URL= # from the database internal connection string
ELIXIR_VERSION=1.12.3 # check Render docs on available versions

https://render.com/docs/elixir-erlang-versions#supported-elixir-versions

Last option before submmitting the form is to make sure Auto Deploy is selected. That mean, that Render will bull latest latest version of either main, master or a specific deploy branch. I just take the original settings and opt for autodeploy on main.

Deployment

Not much to say here. This should now be seup to autodeploy as soon as there is a new push to my main branch on GitHub. if there is a deploy failure, I get an email, and the release fail. Everything is very smooth.

Phoenix Boilerplate

Generate a Phoenix Boilerplate and save hours on your next project.

Try now

SAAS Starter Kit

Get started and save time and resources by using the SAAS Starter Kit built with Phoenix and LiveView.

Learn More

Related Tutorials

Published 13 May

How to create a custom select with Alpine JS and Phoenix LiveView

formsalpinejsliveview
In this tutorial, I want to go through how to build a custom select field that is used in Tailwind UI. And I will build it with Alpine JS and Phoeni..

Published 18 Oct

Building a datatable in Phoenix LiveView

liveviewdatatablesortingpagination
To display a static table on webpage that contains a lot of data is a pretty bad user experience. There are popular javascript libraries that implem..