<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel Easterman</title>
    <description>The latest articles on DEV Community by Daniel Easterman (@daneasterman).</description>
    <link>https://dev.to/daneasterman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1210415%2Fc5bd26e9-9ae0-4f28-afc4-7c371b57858f.jpeg</url>
      <title>DEV Community: Daniel Easterman</title>
      <link>https://dev.to/daneasterman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/daneasterman"/>
    <language>en</language>
    <item>
      <title>Deploy a Python FastAPI Application to Render</title>
      <dc:creator>Daniel Easterman</dc:creator>
      <pubDate>Wed, 10 Jul 2024 10:39:27 +0000</pubDate>
      <link>https://dev.to/appsignal/deploy-a-python-fastapi-application-to-render-5g48</link>
      <guid>https://dev.to/appsignal/deploy-a-python-fastapi-application-to-render-5g48</guid>
      <description>&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why FastAPI?
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The first and most obvious advantage of FastAPI is that it was built with scalability and performance in mind.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;FastAPI also makes it easier for developers to write asynchronous code by simply using the &lt;code&gt;async&lt;/code&gt; keyword when defining asynchronous functions.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Render?
&lt;/h2&gt;

&lt;p&gt;Render is a great option for developers who want to quickly test their applications in a production environment for free.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a FastAPI Demo Application
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;You can &lt;a href="https://github.com/daneasterman/fastapi-render-appsignal" rel="noopener noreferrer"&gt;view, download, or clone the full code&lt;/a&gt; used in this article.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The first thing we need to do is create an empty directory where our project will live. Let's call it &lt;code&gt;fastapi-render-appsignal&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Run the following commands in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;fastapi-render-appsignal
&lt;span class="nb"&gt;cd &lt;/span&gt;flask-heroku-appsignal
&lt;span class="nb"&gt;touch &lt;/span&gt;main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entry point for the project will be &lt;code&gt;main.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, we need to make our project a git repository by running the git initialize command in the root of the directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, create a &lt;code&gt;requirements.txt&lt;/code&gt; file in the project's root directory. Add these two lines to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fastapi
uvicorn[standard]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the installation goes smoothly, you should see the following output in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, in &lt;code&gt;main.py&lt;/code&gt;, copy and paste the following barebones boilerplate code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go line-by-line and explain what is being done in this short code snippet.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;After the import statements, we create an instance of the &lt;code&gt;FastAPI&lt;/code&gt; class and assign it to the variable &lt;code&gt;app&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@app.get("/")&lt;/code&gt; is a Python decorator that tells FastAPI to create an API endpoint via the HTTP GET method at the root URL &lt;code&gt;/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;async def root()&lt;/code&gt; 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.&lt;/li&gt;
&lt;li&gt;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 &lt;code&gt;/&lt;/code&gt; endpoint, our API will automatically respond with a JSON object.&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;We can now run our project using the server package &lt;code&gt;Uvicorn&lt;/code&gt; (that we installed earlier) with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvicorn main:app &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we open our browser at &lt;code&gt;http://127.0.0.1:8000&lt;/code&gt;, we will just see the following plain JSON response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if we add &lt;code&gt;/docs&lt;/code&gt; to the end of the URL, we can take advantage of FastAPI's in-built interactive API documentation capabilities.&lt;/p&gt;

&lt;p&gt;The documentation UI in the screenshot below is provided by Swagger UI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fswagger.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fswagger.png" alt="FastAPI Swagger UI API documentation screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also try another documentation UI style that's automatically included with FastAPI.&lt;/p&gt;

&lt;p&gt;Enter the URL &lt;code&gt;http://127.0.0.1:8000/redoc&lt;/code&gt; in your browser.&lt;/p&gt;

&lt;p&gt;This one is provided by ReDoc:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fredoc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fredoc.png" alt="FastAPI ReDoc API documentation screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy on Render
&lt;/h2&gt;

&lt;p&gt;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 &lt;a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/quickstart-for-repositories" rel="noopener noreferrer"&gt;GitHub’s official docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One of Render’s advantages is that it provides an easy and intuitive way to connect to your GitHub repository.&lt;/p&gt;

&lt;p&gt;First, go to &lt;a href="https://render.com" rel="noopener noreferrer"&gt;render.com&lt;/a&gt; and create a new account with Render (you can use your GitHub credentials to speed things up).&lt;/p&gt;

&lt;p&gt;Then click on the &lt;strong&gt;New&lt;/strong&gt; button and select the option to create a new web service.&lt;/p&gt;

&lt;p&gt;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 &lt;strong&gt;fastapi-render-appsignal&lt;/strong&gt; example project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fgithub-repos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fgithub-repos.png" alt="List of GitHub repos in Render"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fconfig-region.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fconfig-region.png" alt="Render config screen with region option"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Further down the screen, we have a few more important options.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;build command&lt;/strong&gt; will use the &lt;code&gt;requirements.txt&lt;/code&gt; file we created earlier in the project to install all the packages from our project on Render’s remote server.&lt;/p&gt;

&lt;p&gt;Under &lt;strong&gt;start command&lt;/strong&gt;, we will use Uvicorn again in our production environment and tell Render to start the application using &lt;code&gt;main.py&lt;/code&gt; in the root of our project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;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 &lt;a href="https://community.render.com/t/fastapi-python-web-service-deploying-for-hours/6662" rel="noopener noreferrer"&gt;in the Render community forum&lt;/a&gt; and in the post &lt;a href="https://blog.akashrchandran.in/deploying-fastapi-application-to-render" rel="noopener noreferrer"&gt;'Deploying FastAPI application to Render'&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Frender-config.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Frender-config.png" alt="Render config screen with start and build command settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, choose the free option under the list of instance types:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Frender-instance-types.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Frender-instance-types.png" alt="Render instance types with pricing options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lastly, under environment variables, specify the Python version as &lt;code&gt;3.10.7&lt;/code&gt;. Ensure this matches the same version you are using in your local project.&lt;/p&gt;

&lt;p&gt;With our web service configuration done, now we simply click the &lt;strong&gt;Create Web Service&lt;/strong&gt; button and watch the project get deployed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fdeployment-log.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fdeployment-log.png" alt="Render screen showing web service deployment process log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember, this will take a bit of time since we are using the free plan.&lt;/p&gt;

&lt;p&gt;If everything goes smoothly at the end of the deployment process, we should see a final message in Render's logs saying: &lt;strong&gt;"Your service is live"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fservice-live-logs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fservice-live-logs.png" alt="Render screen showing service is live in logs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can click on the public link Render has generated for us and see our &lt;strong&gt;Hello World&lt;/strong&gt; FastAPI example, including the automatic documentation links at &lt;code&gt;/docs&lt;/code&gt; and &lt;code&gt;/redoc&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fdeployed-render-url.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fdeployed-render-url.png" alt="Screen showing service deployed at Render URL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the AppSignal Dashboard for FastAPI and Monitoring Deploys
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;First, &lt;a href="https://appsignal.com/users/sign_up" rel="noopener noreferrer"&gt;sign up for an AppSignal account&lt;/a&gt; (you can do a 30-day free trial, no credit card details required).&lt;br&gt;
Next, add &lt;code&gt;appsignal&lt;/code&gt; and &lt;code&gt;opentelemetry-instrumentation-fastapi&lt;/code&gt; to your &lt;code&gt;requirements.txt&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# requirements.txt
appsignal
opentelemetry-instrumentation-fastapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to create an &lt;code&gt;appsignal.py&lt;/code&gt; configuration file and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;appsignal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Appsignal&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;revision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;revision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;git log --pretty=format:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%h&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; -n 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shell&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CalledProcessError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="n"&gt;appsignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Appsignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fastapi-render-appsignal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;push_api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APPSIGNAL_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;revision&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;revision&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we initialize the &lt;code&gt;Appsignal&lt;/code&gt; object with a few different parameters, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting &lt;code&gt;active&lt;/code&gt; to &lt;code&gt;True&lt;/code&gt; to enable monitoring.&lt;/li&gt;
&lt;li&gt;Providing the &lt;code&gt;name&lt;/code&gt; for our application.&lt;/li&gt;
&lt;li&gt;Putting the API key in an environment variable.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Lastly, we need to update &lt;code&gt;main.py&lt;/code&gt; to finish setting up AppSignal in our FastAPI app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# main.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;opentelemetry.instrumentation.fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPIInstrumentor&lt;/span&gt; &lt;span class="c1"&gt;#new
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;appsignal&lt;/span&gt; &lt;span class="c1"&gt;#new
&lt;/span&gt;
&lt;span class="n"&gt;appsignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;#new
&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/items/{item_id}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;item_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;FastAPIInstrumentor&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;instrument_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#new
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we check out our AppSignal dashboard, the first thing we will see is the &lt;strong&gt;Getting Started&lt;/strong&gt; screen which will provide some suggestions on additional configuration steps to complete:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fgetting-started.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fgetting-started.png" alt="Getting started screen in AppSignal dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But here we'll just focus on ensuring that AppSignal can track our deploys.&lt;/p&gt;

&lt;p&gt;Go to the &lt;strong&gt;Organization&lt;/strong&gt; page in the AppSignal dashboard and then click on &lt;strong&gt;Organization settings&lt;/strong&gt; to activate AppSignal's integration with GitHub. &lt;a href="https://docs.appsignal.com/application/integrations/github/link-to-repo.html" rel="noopener noreferrer"&gt;Check out AppSignal's official docs on linking your repo&lt;/a&gt; for step-by-step instructions.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;In our case, we simply need to push to our main branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is set up correctly, we should see AppSignal tracking our deploys and any errors associated with each deploy commit hash in the &lt;strong&gt;Deploys&lt;/strong&gt; section of the dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fdeploys-fastapi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.appsignal.com%2Fimages%2Fblog%2F2024-06%2Fdeploys-fastapi.png" alt="Deploys screen in AppSignal dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this guide, we covered a lot of ground! First, we briefly introduced some of the advantages and disadvantages of choosing FastAPI and Render.&lt;/p&gt;

&lt;p&gt;Then, we created a simple FastAPI app, deployed it to Render, and ended by monitoring those deploys with AppSignal.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Python posts as soon as they get off the press, &lt;a href="https://blog.appsignal.com/python-wizardry" rel="noopener noreferrer"&gt;subscribe to our Python Wizardry newsletter and never miss a single post!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>python</category>
    </item>
    <item>
      <title>How to Deploy a Python Flask app with Heroku</title>
      <dc:creator>Daniel Easterman</dc:creator>
      <pubDate>Wed, 20 Dec 2023 15:09:33 +0000</pubDate>
      <link>https://dev.to/appsignal/how-to-deploy-a-python-flask-app-with-heroku-3n50</link>
      <guid>https://dev.to/appsignal/how-to-deploy-a-python-flask-app-with-heroku-3n50</guid>
      <description>&lt;p&gt;In this tutorial, we will build a simple Flask app that is primed and ready to deploy to Heroku.&lt;/p&gt;

&lt;p&gt;Once the bare bones of the app are built, we will guide you through the setup process on GitHub and Heroku so that you can start making automatic deploys in no time.&lt;/p&gt;

&lt;p&gt;But before we dive straight into the code, why choose Flask and Heroku in the first place?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Flask for Python?
&lt;/h2&gt;

&lt;p&gt;Flask is a super-minimalistic web framework for Python. It provides only the absolute core functionality needed to build web applications in a small and nimble package.&lt;/p&gt;

&lt;p&gt;One major advantage of this approach is that Flask provides web developers with maximum flexibility to design and build their app from the very beginning.&lt;/p&gt;

&lt;p&gt;On the other hand, frameworks such as Django prefer the "batteries-included" philosophy. This means more is taken care of for you out-of-the-box, but there will be more boilerplate code. The structure of your application is more rigid and harder to change later on.&lt;/p&gt;

&lt;p&gt;Also, as the industry moves away from big code "monoliths" built on frameworks like Django, and towards smaller microservice architecture, it has never been a better time to get familiar with Flask.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Heroku?
&lt;/h2&gt;

&lt;p&gt;When Heroku launched in 2007, it was one of the first cloud platforms renowned for its user-friendly interface and ease of use. Using Heroku was a huge time-saver, as it made deploying web applications much easier than configuring all your infrastructure from scratch using AWS. In fact, Heroku itself is built on AWS infrastructure. Another advantage was the fact that you could deploy your hobby app with a full Postgres database totally for free.&lt;/p&gt;

&lt;p&gt;Since then, several other cloud services have sprung up to challenge Heroku's first-mover advantage in the sector of cloud computing known as Platform-as-a-Service (PaaS).&lt;/p&gt;

&lt;p&gt;But Heroku still retains one significant edge over the newer cloud providers: its extensive library of third-party add-ons.&lt;/p&gt;

&lt;p&gt;If you need functionality for your app like error tracking or performance monitoring (which, incidentally, &lt;a href="https://www.appsignal.com/python"&gt;AppSignal&lt;/a&gt; provides) you can simply install an add-on for that on Heroku's interface and get started immediately. For many developers, this speed and convenience might make the difference between shipping or not shipping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Python Flask Demo App for Heroku Deployment
&lt;/h2&gt;

&lt;p&gt;The very first thing we need to do is create an empty Flask project. Lets call it &lt;code&gt;flask-heroku-appsignal&lt;/code&gt;. We'll also create the main entry point file for our project, &lt;code&gt;app.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;flask_heroku_appsignal
&lt;span class="nb"&gt;cd &lt;/span&gt;flask-heroku-appsignal
&lt;span class="nb"&gt;touch &lt;/span&gt;app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we'll make our project a git repository by running the git initialize command in the root of the directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the way, if you want to view the full code for this article at any point, &lt;a href="https://github.com/daneasterman/flask-heroku-appsignal"&gt;download or clone it here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, we need to install the core dependencies, which include Flask itself, &lt;code&gt;python-dotenv&lt;/code&gt; (to manage environment variables), and &lt;code&gt;gunicorn&lt;/code&gt;, which will act as the "bridge" between Heroku's web servers and our web application.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;requirements.txt&lt;/code&gt; file in the root of the project and just add the dependency names to it (you don't need to include the version numbers):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Flask
python-dotenv
gunicorn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything goes smoothly, we should see some output that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Collecting Flask
  Using cached Flask-2.2.3-py3-none-any.whl &lt;span class="o"&gt;(&lt;/span&gt;101 kB&lt;span class="o"&gt;)&lt;/span&gt;
Collecting python-dotenv
  Using cached python_dotenv-1.0.0-py3-none-any.whl &lt;span class="o"&gt;(&lt;/span&gt;19 kB&lt;span class="o"&gt;)&lt;/span&gt;
Collecting Werkzeug&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;2.2.2
  Using cached Werkzeug-2.2.3-py3-none-any.whl &lt;span class="o"&gt;(&lt;/span&gt;233 kB&lt;span class="o"&gt;)&lt;/span&gt;
Collecting itsdangerous&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;2.0
  Using cached itsdangerous-2.1.2-py3-none-any.whl &lt;span class="o"&gt;(&lt;/span&gt;15 kB&lt;span class="o"&gt;)&lt;/span&gt;
Collecting click&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;8.0
  Using cached click-8.1.3-py3-none-any.whl &lt;span class="o"&gt;(&lt;/span&gt;96 kB&lt;span class="o"&gt;)&lt;/span&gt;
Collecting Jinja2&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;3.0
  Using cached Jinja2-3.1.2-py3-none-any.whl &lt;span class="o"&gt;(&lt;/span&gt;133 kB&lt;span class="o"&gt;)&lt;/span&gt;
Collecting MarkupSafe&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;2.0
  Using cached MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl &lt;span class="o"&gt;(&lt;/span&gt;13 kB&lt;span class="o"&gt;)&lt;/span&gt;
Installing collected packages: python-dotenv, MarkupSafe, itsdangerous, click, Werkzeug, Jinja2, Flask
Successfully installed Flask-2.2.3 Jinja2-3.1.2 MarkupSafe-2.1.2 Werkzeug-2.2.3 click-8.1.3 itsdangerous-2.1.2 python-dotenv-1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Preparing for Heroku Deployment
&lt;/h3&gt;

&lt;p&gt;Now that all our basic project foundations are in place, let’s start building and configuring our Flask app with deployment to Heroku in mind.&lt;/p&gt;

&lt;p&gt;First, let's copy this super-simple "hello world" code into &lt;code&gt;app.py&lt;/code&gt; to check everything is working as expected so far:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then type &lt;code&gt;flask run&lt;/code&gt; in the terminal. We should see the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;*&lt;/span&gt; Debug mode: off
WARNING: This is a development server. Do not use it &lt;span class="k"&gt;in &lt;/span&gt;a production deployment. Use a production WSGI server instead.
 &lt;span class="k"&gt;*&lt;/span&gt; Running on http://127.0.0.1:5000
Press CTRL+C to quit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we go to &lt;code&gt;localhost:5000&lt;/code&gt;, we will see the &lt;code&gt;Hello World!&lt;/code&gt; string printed in the browser.&lt;/p&gt;

&lt;p&gt;At this point, I have a nice time-saving Flask tip to share with you that isn't mentioned in most Flask tutorials.&lt;/p&gt;

&lt;p&gt;By adding the simple one-liner below in your &lt;code&gt;.env&lt;/code&gt; at the root of the project, you can save lots of time. You won't have to stop and start your local server every time you want to make changes to your backend code. While this doesn't sound like a huge thing, these small changes add up to loads of compounded saved time over the long run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FLASK_DEBUG=True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the “debug” name suggests, this setting will provide a nicely formatted error read-out in the browser to make it easier to debug your code.&lt;/p&gt;

&lt;p&gt;Also, ensure that the &lt;code&gt;.env&lt;/code&gt; file is included in your project's &lt;code&gt;.gitignore&lt;/code&gt; so that it's not tracked by git. This means it will not be picked up by GitHub and Heroku (as we don’t want the debug mode to be part of our production settings).&lt;/p&gt;

&lt;p&gt;After making this change, the output on our terminal will display &lt;code&gt;Debug mode&lt;/code&gt; as &lt;code&gt;on&lt;/code&gt; with the Debugger PIN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;*&lt;/span&gt; Debug mode: on
WARNING: This is a development server. Do not use it &lt;span class="k"&gt;in &lt;/span&gt;a production deployment. Use a production WSGI server instead.
 &lt;span class="k"&gt;*&lt;/span&gt; Running on http://127.0.0.1:5000
Press CTRL+C to quit
 &lt;span class="k"&gt;*&lt;/span&gt; Restarting with &lt;span class="nb"&gt;stat&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; Debugger is active!
 &lt;span class="k"&gt;*&lt;/span&gt; Debugger PIN: 133-697-373
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Development and Production Settings In Our Python Flask App
&lt;/h3&gt;

&lt;p&gt;Next, we want to make a clear distinction between the development and production settings in our Flask app. This is an important step in preparing for deployment to Heroku. To do this, we will create a &lt;code&gt;config.py&lt;/code&gt; file in the root of the project and add the following code with three classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
 &lt;span class="n"&gt;DEVELOPMENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
 &lt;span class="n"&gt;CSRF_ENABLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
 &lt;span class="n"&gt;ASSETS_DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductionConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DevelopmentConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="n"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
 &lt;span class="n"&gt;DEVELOPMENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
 &lt;span class="n"&gt;TEMPLATES_AUTO_RELOAD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
 &lt;span class="n"&gt;ASSETS_DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back in &lt;code&gt;app.py&lt;/code&gt;, add the following two lines before the index route function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;env_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PROD_APP_SETTINGS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;config.DevelopmentConfig&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now the full &lt;code&gt;app.py&lt;/code&gt; will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;
&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;env_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PROD_APP_SETTINGS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;config.DevelopmentConfig&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essentially, the code above says that if we find a key called &lt;code&gt;PROD_APP_SETTINGS&lt;/code&gt; in our environment, the config for our app should be set to &lt;code&gt;config.ProductionConfig&lt;/code&gt;. Otherwise, we can safely assume we are in development mode and set it to &lt;code&gt;config.DevelopmentConfig&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we are ready to set up our app in Heroku's web interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Setup
&lt;/h2&gt;

&lt;p&gt;Before setting up on Heroku, we first need to create a repository on GitHub.&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="https://github.com/"&gt;github.com&lt;/a&gt; and create a new account (if you don't have one already).&lt;/p&gt;

&lt;p&gt;We can call our GitHub repository the same name as our local Flask project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lpy1uaBC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-12/github-repo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lpy1uaBC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-12/github-repo.png" alt="Create GitHub Repository Screenshot" width="800" height="757"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we simply need to follow GitHub's instructions and push the code from our existing local repository to the remote one.&lt;/p&gt;

&lt;p&gt;To double-check that the local and remote repositories have been linked correctly, run this command in the project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should get something very similar to the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;origin  https://github.com/daneasterman/flask-heroku-appsignal.git &lt;span class="o"&gt;(&lt;/span&gt;fetch&lt;span class="o"&gt;)&lt;/span&gt;
origin  https://github.com/daneasterman/flask-heroku-appsignal.git &lt;span class="o"&gt;(&lt;/span&gt;push&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the GitHub steps complete, we can start getting set up on Heroku by first creating a new app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heroku Deployment
&lt;/h2&gt;

&lt;p&gt;We need to make sure that we have Heroku's special &lt;code&gt;Procfile&lt;/code&gt; at the root of our project. The Procfile is a configuration text file specifying the various process types that will run when your app starts up. Without this, your app will not run on Heroku.&lt;/p&gt;

&lt;p&gt;Copy the line below and add it to your Procfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;web: gunicorn app:app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, remember the &lt;code&gt;config.py&lt;/code&gt; we created in the previous section? We need to update our configuration in Heroku so that the app runs on our production settings, with &lt;code&gt;DEBUG&lt;/code&gt; set to &lt;code&gt;False&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, click on the Setting tab on your Heroku dashboard. Then click the &lt;strong&gt;Reveal Config Vars&lt;/strong&gt; button. Add the variable &lt;code&gt;PROD_APP_SETTINGS&lt;/code&gt; and the value &lt;code&gt;config.ProductionConfig&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, we need to connect our GitHub repository to Heroku. Click on the &lt;strong&gt;"Connect to GitHub"&lt;/strong&gt; button. Then in the section that appears underneath, search for our &lt;code&gt;flask-heroku-appsignal&lt;/code&gt; repository, and finally click on the second &lt;strong&gt;"Connect"&lt;/strong&gt; button below.&lt;/p&gt;

&lt;p&gt;Then click the &lt;strong&gt;"Enable Automatic Deploys"&lt;/strong&gt; button. This means that every time you push your code to the main branch on GitHub, it will trigger an automatic deployment to Heroku.&lt;/p&gt;

&lt;p&gt;Unfortunately, Heroku doesn't provide a free tier for demo apps anymore. So to complete the proof-of-concept for our &lt;code&gt;flask-heroku-appsignal&lt;/code&gt; app, we need to purchase a dyno-type subscription.&lt;/p&gt;

&lt;p&gt;This is where Heroku is a little cheeky and automatically puts you in the slightly more expensive &lt;strong&gt;Basic Plan&lt;/strong&gt;. To change this, click on the &lt;strong&gt;Resources&lt;/strong&gt; tab and then click: &lt;strong&gt;Change Dyno Type&lt;/strong&gt;, which will bring up a modal screen. Finally select the &lt;strong&gt;Eco&lt;/strong&gt; dyno, which will be absolutely fine for our purposes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3RjHBsgx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-12/dyno-types.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3RjHBsgx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.appsignal.com/images/blog/2023-12/dyno-types.png" alt="Heroku Dyno Types Screen" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we're done!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;That concludes this introduction to deploying your Flask app to Heroku. Once you build out your web app with more functionality, you can think about installing the &lt;a href="https://devcenter.heroku.com/articles/appsignal"&gt;AppSignal add-on for Heroku&lt;/a&gt;, which now supports Python and Flask apps.&lt;/p&gt;

&lt;p&gt;With this add-on, you can track errors, monitor performance, get access to advanced metric dashboards, and more. Happy building!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Python posts as soon as they get off the press, &lt;a href="https://dev.to/python-wizardry"&gt;subscribe to our Python Wizardry newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
