Deploy a Python FastAPI Application to Render
Tags: fastapi, python
Published: 2024-07-10 10:39:27

In the world of Python frameworks, FastAPI is the new kid on the block and a great choice for building APIs. Equally, Render is a good option for developers who want to quickly test their applications in a production environment for free.

In this post, we'll run through how to deploy a FastAPI app to Render. First, though, let's explore why FastAPI and Render are often chosen by developers.

## Why FastAPI?

FastAPI is a high-performance microframework used primarily for building APIs (the clue is in the name). As such, FastAPI offers several advantages over older, better-known frameworks such as Django and Flask.

The first and most obvious advantage of FastAPI is that it was built with scalability and performance in mind.

For example, FastAPI is based on an asynchronous ASGI server rather than the older WSGI used by Django and other frameworks. ASGI servers can handle multiple requests simultaneously (concurrently). This is often seen as a better option for apps that need to handle high levels of user traffic.

FastAPI also makes it easier for developers to write asynchronous code by simply using the `async` keyword when defining asynchronous functions.

But FastAPI's shiny "newness" is also its main drawback. Because it was only introduced in 2018, FastAPI has a much smaller community and fewer learning resources (such as coding tutorials) compared to the more established frameworks. This is something to bear in mind when choosing FastAPI for your next project.

## Why Render?

Render is a great option for developers who want to quickly test their applications in a production environment for free.

With Render, you don't even have to enter your credit card details to gain access to the free tier. So unlike other cloud services, there is no way to rack up charges by mistake.

As we will see in the section below, Render also provides an excellent overall developer experience with a clean, very easy-to-use UI and smooth integration with Git and GitHub. An added bonus is that any app you host on Render gets a free TLS certificate right out of the box.

The downside with Render's free tier is that it can take a long time for deployments to complete. Once this starts to become an issue, you might want to consider upgrading to one of the paid plans.

## Create a FastAPI Demo Application

_You can [view, download, or clone the full code](https://github.com/daneasterman/fastapi-render-appsignal) used in this article._

The first thing we need to do is create an empty directory where our project will live. Let's call it `fastapi-render-appsignal`.

Run the following commands in your terminal:

```shell
mkdir fastapi-render-appsignal
cd flask-heroku-appsignal
touch main.py
```

The entry point for the project will be `main.py`.

Next, we need to make our project a git repository by running the git initialize command in the root of the directory:

```shell
git init
```

Also, create a `requirements.txt` file in the project's root directory. Add these two lines to the file:

```text
fastapi
uvicorn[standard]
```

Then run:

```shell
pip install -r requirements.txt
```

If the installation goes smoothly, you should see the following output in the terminal:

```shell
Installing collected packages: websockets, uvloop, typing-extensions, sniffio, pyyaml, python-dotenv, idna, httptools, h11, exceptiongroup, click, annotated-types, uvicorn, pydantic-core, anyio, watchfiles, starlette, pydantic, fastapi
Successfully installed annotated-types-0.6.0 anyio-4.2.0 click-8.1.7 exceptiongroup-1.2.0 fastapi-0.109.0 h11-0.14.0 httptools-0.6.1 idna-3.6 pydantic-2.5.3 pydantic-core-2.14.6 python-dotenv-1.0.1 pyyaml-6.0.1 sniffio-1.3.0 starlette-0.35.1 typing-extensions-4.9.0 uvicorn-0.27.0 uvloop-0.19.0 watchfiles-0.21.0 websockets-12.0
```

Now, in `main.py`, copy and paste the following barebones boilerplate code:

```python
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
	return {"message": "Hello World"}
```

Let's go line-by-line and explain what is being done in this short code snippet.

1. After the import statements, we create an instance of the `FastAPI` class and assign it to the variable `app`.
2. `@app.get("/")` is a Python decorator that tells FastAPI to create an API endpoint via the HTTP GET method at the root URL `/`.
3. `async def root()` defines an asynchronous function named root. We are using the async keyword here because FastAPI is built to work with asynchronous I/O operations. This means it can handle concurrent requests, which is better for performance.
4. In the body of the function, we return a Python dictionary which FastAPI helpfully converts to JSON for us. So, when the user goes to the root `/` endpoint, our API will automatically respond with a JSON object.

<Banner lang="python" />

We can now run our project using the server package `Uvicorn` (that we installed earlier) with the following command:

```shell
uvicorn main:app --reload
```

If we open our browser at `http://127.0.0.1:8000`, we will just see the following plain JSON response:

```json
{ "message": "Hello World" }
```

But if we add `/docs` to the end of the URL, we can take advantage of FastAPI's in-built interactive API documentation capabilities.

The documentation UI in the screenshot below is provided by Swagger UI:

![FastAPI Swagger UI API documentation screen](https://blog.appsignal.com/images/blog/2024-06/swagger.png)

You can also try another documentation UI style that's automatically included with FastAPI.

Enter the URL `http://127.0.0.1:8000/redoc` in your browser.

This one is provided by ReDoc:

![FastAPI ReDoc API documentation screen](https://blog.appsignal.com/images/blog/2024-06/redoc.png)

## Deploy on Render

This part assumes you have already created a repository for this project on GitHub. If you need instructions on how to do this, check out [GitHub’s official docs](https://docs.github.com/en/repositories/creating-and-managing-repositories/quickstart-for-repositories).

One of Render’s advantages is that it provides an easy and intuitive way to connect to your GitHub repository.

First, go to [render.com](https://render.com) and create a new account with Render (you can use your GitHub credentials to speed things up).

Then click on the **New** button and select the option to create a new web service.

After linking your GitHub account, you should see the screen below, which provides a list of GitHub repos to connect to Render. Let's select our **fastapi-render-appsignal** example project.

![List of GitHub repos in Render](https://blog.appsignal.com/images/blog/2024-06/github-repos.png)

This will then take us to the main configuration screen. Under region, simply select the region closest to your location (since I’m based in the UK, I will choose Frankfurt):

![Render config screen with region option](https://blog.appsignal.com/images/blog/2024-06/config-region.png)

Further down the screen, we have a few more important options.

The **build command** will use the `requirements.txt` file we created earlier in the project to install all the packages from our project on Render’s remote server.

Under **start command**, we will use Uvicorn again in our production environment and tell Render to start the application using `main.py` in the root of our project.

**Note:** _You must explicitly tell Render which host and port to use (unlike when using other servers like gunicorn). Unfortunately, this is not mentioned in any of the official Render documentation but I found the solution [in the Render community forum](https://community.render.com/t/fastapi-python-web-service-deploying-for-hours/6662) and in the post ['Deploying FastAPI application to Render'](https://blog.akashrchandran.in/deploying-fastapi-application-to-render)._

![Render config screen with start and build command settings](https://blog.appsignal.com/images/blog/2024-06/render-config.png)

Next, choose the free option under the list of instance types:

![Render instance types with pricing options](https://blog.appsignal.com/images/blog/2024-06/render-instance-types.png)

Lastly, under environment variables, specify the Python version as `3.10.7`. Ensure this matches the same version you are using in your local project.

With our web service configuration done, now we simply click the **Create Web Service** button and watch the project get deployed:

![Render screen showing web service deployment process log](https://blog.appsignal.com/images/blog/2024-06/deployment-log.png)

Remember, this will take a bit of time since we are using the free plan.

If everything goes smoothly at the end of the deployment process, we should see a final message in Render's logs saying: **"Your service is live"**.

![Render screen showing service is live in logs](https://blog.appsignal.com/images/blog/2024-06/service-live-logs.png)

Now we can click on the public link Render has generated for us and see our **Hello World** FastAPI example, including the automatic documentation links at `/docs` and `/redoc`:

![Screen showing service deployed at Render URL](https://blog.appsignal.com/images/blog/2024-06/deployed-render-url.png)

## Installing the AppSignal Dashboard for FastAPI and Monitoring Deploys

It's great that we now have a basic FastAPI app running and deployed to Render, but what if something goes wrong? Even with the best manual and automated testing, the reality is that errors and bugs happen in software development. The key thing is to get alerted as soon as errors happen and to quickly identify where the problem is in the code.

In this section of the tutorial, we are going to specifically look at how to enable AppSignal to monitor your deployments. This part of the setup is crucial for you to see which errors are associated with a specific deployment. This will allow you to diagnose and fix problems in your app quickly and efficiently.

First, [sign up for an AppSignal account](https://appsignal.com/users/sign_up) (you can do a 30-day free trial, no credit card details required).
Next, add `appsignal` and `opentelemetry-instrumentation-fastapi` to your `requirements.txt` file:

```text
# requirements.txt
appsignal
opentelemetry-instrumentation-fastapi
```

Then run:

```shell
pip install -r requirements.txt
```

Now we need to create an `appsignal.py` configuration file and add the following code:

```python
import os
import subprocess
from appsignal import Appsignal
from dotenv import load_dotenv
load_dotenv()

revision = None
try:
    revision = subprocess.check_output(
        "git log --pretty=format:'%h' -n 1", shell=True
    ).strip()
except subprocess.CalledProcessError:
  pass


appsignal = Appsignal(
    active=True,
    name="fastapi-render-appsignal",
    push_api_key=os.getenv("APPSIGNAL_API_KEY"),
    revision=revision,
)
```

In the code above, we initialize the `Appsignal` object with a few different parameters, including:

- Setting `active` to `True` to enable monitoring.
- Providing the `name` for our application.
- Putting the API key in an environment variable.

But the key parameter to enable deploy tracking is the `revision` parameter. Inside the `try-except` block (above the AppSignal initialization code), we fetch the latest commit hash so AppSignal can keep track of our deploys.

Lastly, we need to update `main.py` to finish setting up AppSignal in our FastAPI app:

```python
# main.py
from fastapi import FastAPI
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor #new
import appsignal #new

appsignal.start() #new

app = FastAPI()

@app.get("/")
async def root():
	return {"message": "Hello World"}

@app.get("/items/{item_id}")
async def get_item(item_id: int):
	return {"item_id": item_id}

FastAPIInstrumentor().instrument_app(app) #new
```

When we check out our AppSignal dashboard, the first thing we will see is the **Getting Started** screen which will provide some suggestions on additional configuration steps to complete:

![Getting started screen in AppSignal dashboard](https://blog.appsignal.com/images/blog/2024-06/getting-started.png)

But here we'll just focus on ensuring that AppSignal can track our deploys.

Go to the **Organization** page in the AppSignal dashboard and then click on **Organization settings** to activate AppSignal's integration with GitHub. [Check out AppSignal's official docs on linking your repo](https://docs.appsignal.com/application/integrations/github/link-to-repo.html) for step-by-step instructions.

With the GitHub integration set up and your repo linked, all you need to do now is trigger a deployment in Render for AppSignal to start monitoring your deploys.

In our case, we simply need to push to our main branch:

```shell
git push origin main
```

If everything is set up correctly, we should see AppSignal tracking our deploys and any errors associated with each deploy commit hash in the **Deploys** section of the dashboard:

![Deploys screen in AppSignal dashboard](https://blog.appsignal.com/images/blog/2024-06/deploys-fastapi.png)

And that's it!

## Wrapping Up

In this guide, we covered a lot of ground! First, we briefly introduced some of the advantages and disadvantages of choosing FastAPI and Render.

Then, we created a simple FastAPI app, deployed it to Render, and ended by monitoring those deploys with AppSignal.

Happy coding!

**P.S. If you'd like to read Python posts as soon as they get off the press, [subscribe to our Python Wizardry newsletter and never miss a single post!](https://blog.appsignal.com/python-wizardry)**