In our previous blog post we helped you create your first REST API project. Now it's time to deploy it!

Deploying your app to the cloud will make it accessible via an URL. This means that you will be able to share it with your friends and use it on the web without having to run it locally!

In this post, we'll show you how to deploy your REST API project for free using Render.com and Fly.io.

Deploying to Render.com

We'll first deploy our app using Render.com since it doesn't need (almost) any changes in the project. The only change that needs to be made is adding gunicorn to the requirements.txt file. We won't cover gunicorn in this blog post but you can check out the official documentation for more info on it.

After you've done that, push your updated project to GitHub since you will need a Git repository to deploy your project. If you're not sure how to do it, we've got you covered!

Now that your project is all set, let's deploy it!

You will first need to sign up for Render.com. I recommend signing up with your GitHub account since it makes some tasks easier later on.

After you've logged in, access the dashboard. At the top-right of the page, you will see the +New button. Press it and select web service. The next step will be connecting a repository. If you've signed up with your GitHub account then you should have a list of available repositories to select from. If you didn't connect your GitHub account, you will need to do it now and you will see a Connect GitHub button.

Now that your GitHub is connected, select the repository containing your app. You will then be redirected to the main page of this setup:

Empty form

You will first need to choose a name for your web service. Try keeping it close to the app's name since it will make organizing easier later on when you start deploying new apps. For the environment, choose Python3.

When you choose Python3 as the environment, Render will run the application using Python 3.7 by default. If you want to change the Python version, you can do so with an environment variable called PYTHON_VERSION, and the value is the version of Python you want to use, such as 3.10.8. More on that below, when we talk about environment variables.

The next part is the region. You should select a region that is as close to you and your database as possible since it will affect performance. For example, I am located in Serbia and I've got a database in Stockholm so I will choose a server in Frankfurt since it's the closest available server to me and my database.

The branch that I recommend using for your web service is main or master since you will only want to deploy reviewed and approved code.

The next two steps are setting commands used to run your code. Build command is a command that runs in the root directory of the repository whenever a new version of the code is pushed or when you deploy it manually. The build command will be pip install -r requirements.txt since we want to make sure that all the modules are installed before we run the app.

The start command runs in the root directory of your app and handles starting its processes. The start command for our project will be gunicorn app:app. The start command can access environment variables that are set in Render. This is important since we will set an environment variable later.

Using app factories?

If you are using an app factory, with a function such as create_app(), then the start command will likely be gunicorn "app:create_app()".

To finish setup, select the free plan and create a web service. The build will start, but it will fail since we have one more thing to do.

This is how the finished setup looks like before the next step:

Setup

Navigate to the Environment page. In the Environment Variables section, press Add Environment Variable. The key that we will use is DATABASE_URL and the value is the URL of your database (usually if you use a MongoDB database instead of PostgreSQL, the environment variable will be called MONGODB_URI). Deployment should restart after you've set the variable. If it doesn't, start a new deploy manually.

Environment Variables

Different Python version

Like we mentioned above, Render will use Python 3.7 by default. If you want to use a different Python version, create another environment variable called PYTHON_VERSION, and give it the value of the Python version you want to use, such as 3.10.8.

If you've done everything, congrats! Your app is now deployed! In the top left, below the name of your app, you will see a link that you can copy to use in the browser or in Postman, if you want to check out your API!

Deploying to Fly.io

Deploying to Fly.io is a bit more complicated. For this part of the project, you will need a Docker image. As always, we've got you covered! You can read our intro to Docker where we cover everything that you need for this deployment.

The Docker image that we use for deploying our app looks like this:

FROM python:3.10
EXPOSE 8080
WORKDIR /app
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "2", "app:app"]

After you've created the Docker image, the next step is to create an account on Fly.io. Then, you will need to download their CLI tool called Flyctl. The complete guide on setting up the tool and registration can be found in the official documentation. If you've signed up successfully, you should be able to log in to your Fly account.

Once you've logged in to your account, open a terminal in the working folder of your project and type flyctl launch. This will create a new app for you and you will be able to choose configuration details. Choose a server in a region as close to you as possible since it will make your app run faster once it's deployed. In case this command doesn't work for you, create a file named fly.toml with this content:

app = "rest-apis"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []

[env]

[experimental]
  allowed_public_ports = []
  auto_rollback = true

[[services]]
  http_checks = []
  internal_port = 8080
  processes = ["app"]
  protocol = "tcp"
  script_checks = []
  [services.concurrency]
    hard_limit = 25
    soft_limit = 20
    type = "connections"

  [[services.ports]]
    force_https = true
    handlers = ["http"]
    port = 80

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 443

  [[services.tcp_checks]]
    grace_period = "1s"
    interval = "15s"
    restart_limit = 0
    timeout = "2s"

Another thing to notice is that Fly.io provides you with a free database. We suggest you create a new database while configuring your Fly app. If you want to use a third-party database, make sure to add the database URL as a secret variable to your Fly app. Run the following command: flyctl secrets set DATABASE_URL=url. This step won't be needed if you've chosen the first option since Fly will automatically add a secret to your app.

Once you've done this, you can navigate to your dashboard and you will see your app running! If you click on your app, you will be able to get the URL which you can use to test your app using Postman. There are also some cool features like monitoring and metrics!

Comparing the two

Since this post is based on free app deployment, we wanted to close this blog by comparing the free tiers of each of the clouds that we used.

Let's start with Render. Render's advantage is that the deployment process is simple, as we've seen already. It also has cool metrics options with the ability to search the logs, which can be quite useful. It doesn't have a database included in its free tier without adding a credit card. You can use a database for free after that, but only for 90 days. After 90 days have passed, the database will be deleted. This means that you will need to go with a third-party database in Render's free tier. The main disadvantage of Render is slow builds. Depending on the cloud's load, build time can get into the realm of five-plus minutes, with some users reporting even double that time.

When it comes to Fly.io, the registration and deployment process are more complicated, but the speed difference is noticeable. It relies less on UI than Render does, but they do have a great CLI tool which works great. However, the documentation is still lacking in some areas so you will often have to resort to Fly's community to help you solve your problem. The Postgres database is included in the free plan, as well as Redis.

Conclusion

Both of the clouds have their advantages: Render has a more developed UI and logs, while Fly.io is better for those whose main concern is speed. We've covered both of them so you can try them out and choose the best one for you!

If you've enjoyed this blog post and want to learn more about REST API development, consider enrolling in our course REST APIs with Flask and Python. It covers building a complete REST API using PostgreSQL and Docker, as well as SQLAlchemy, database migrations, and authentication!