docs/en/docs/deployment/concepts.md::Deployments Concepts { #deployments-concepts }::L1

# Doc: docs/en/docs/deployment/concepts.md | Page: Deployments Concepts { #deployments-concepts } | Section: Deployments Concepts { #deployments-concepts }
# Deployments Concepts { #deployments-concepts }

When deploying a **FastAPI** application, or actually, any type of web API, there are several concepts that you probably care about, and using them you can find the **most appropriate** way to **deploy your application**.

Some of the important concepts are:

* Security - HTTPS
* Running on startup
* Restarts
* Replication (the number of processes running)
* Memory
* Previous steps before starting

We'll see how they would affect **deployments**.

In the end, the ultimate objective is to be able to **serve your API clients** in a way that is **secure**, to **avoid disruptions**, and to use the **compute resources** (for example remote servers/virtual machines) as efficiently as possible. 🚀

I'll tell you a bit more about these **concepts** here, and that would hopefully give you the **intuition** you would need to decide how to deploy your API in very different environments, possibly even in **future** ones that don't exist yet.

By considering these concepts, you will be able to **evaluate and design** the best way to deploy **your own APIs**.

In the next chapters, I'll give you more **concrete recipes** to deploy FastAPI applications.

But for now, let's check these important **conceptual ideas**. These concepts also apply to any other type of web API. 💡


docs/en/docs/deployment/concepts.md::Security - HTTPS { #security-https }::L26

# Doc: docs/en/docs/deployment/concepts.md | Page: Deployments Concepts { #deployments-concepts } | Section: Security - HTTPS { #security-https }
## Security - HTTPS { #security-https }

In the [previous chapter about HTTPS](https.md) we learned about how HTTPS provides encryption for your API.

We also saw that HTTPS is normally provided by a component **external** to your application server, a **TLS Termination Proxy**.

And there has to be something in charge of **renewing the HTTPS certificates**, it could be the same component or it could be something different.

### Example Tools for HTTPS { #example-tools-for-https }

Some of the tools you could use as a TLS Termination Proxy are:

* Traefik
    * Automatically handles certificate renewals ✨
* Caddy
    * Automatically handles certificate renewals ✨
* Nginx
    * With an external component like Certbot for certificate renewals
* HAProxy
    * With an external component like Certbot for certificate renewals
* Kubernetes with an Ingress Controller like Nginx
    * With an external component like cert-manager for certificate renewals
* Handled internally by a cloud provider as part of their services (read below 👇)

Another option is that you could use a **cloud service** that does more of the work including setting up HTTPS. It could have some restrictions or charge you more, etc. But in that case, you wouldn't have to set up a TLS Termination Proxy yourself.

I'll show you some concrete examples in the next chapters.

---

Then the next concepts to consider are all about the program running your actual API (e.g. Uvicorn).


docs/en/docs/deployment/concepts.md::Program and Process { #program-and-process }::L58

# Doc: docs/en/docs/deployment/concepts.md | Page: Deployments Concepts { #deployments-concepts } | Section: Program and Process { #program-and-process }
## Program and Process { #program-and-process }

We will talk a lot about the running "**process**", so it's useful to have clarity about what it means, and what's the difference with the word "**program**".

### What is a Program { #what-is-a-program }

The word **program** is commonly used to describe many things:

* The **code** that you write, the **Python files**.
* The **file** that can be **executed** by the operating system, for example: `python`, `python.exe` or `uvicorn`.
* A particular program while it is **running** on the operating system, using the CPU, and storing things in memory. This is also called a **process**.

### What is a Process { #what-is-a-process }

The word **process** is normally used in a more specific way, only referring to the thing that is running in the operating system (like in the last point above):

* A particular program while it is **running** on the operating system.
    * This doesn't refer to the file, nor to the code, it refers **specifically** to the thing that is being **executed** and managed by the operating system.
* Any program, any code, **can only do things** when it is being **executed**. So, when there's a **process running**.
* The process can be **terminated** (or "killed") by you, or by the operating system. At that point, it stops running/being executed, and it can **no longer do things**.
* Each application that you have running on your computer has some process behind it, each running program, each window, etc. And there are normally many processes running **at the same time** while a computer is on.
* There can be **multiple processes** of the **same program** running at the same time.

If you check out the "task manager" or "system monitor" (or similar tools) in your operating system, you will be able to see many of those processes running.

And, for example, you will probably see that there are multiple processes running the same browser program (Firefox, Chrome, Edge, etc). They normally run one process per tab, plus some other extra processes.

<img class="shadow" src="/img/deployment/concepts/image01.png">

---

Now that we know the difference between the terms **process** and **program**, let's continue talking about deployments.


docs/en/docs/deployment/concepts.md::Running on Startup { #running-on-startup }::L91

# Doc: docs/en/docs/deployment/concepts.md | Page: Deployments Concepts { #deployments-concepts } | Section: Running on Startup { #running-on-startup }
## Running on Startup { #running-on-startup }

In most cases, when you create a web API, you want it to be **always running**, uninterrupted, so that your clients can always access it. This is of course, unless you have a specific reason why you want it to run only in certain situations, but most of the time you want it constantly running and **available**.

### In a Remote Server { #in-a-remote-server }

When you set up a remote server (a cloud server, a virtual machine, etc.) the simplest thing you can do is use `fastapi run` (which uses Uvicorn) or something  similar, manually, the same way you do when developing locally.

And it will work and will be useful **during development**.

But if your connection to the server is lost, the **running process** will probably die.

And if the server is restarted (for example after updates, or migrations from the cloud provider) you probably **won't notice it**. And because of that, you won't even know that you have to restart the process manually. So, your API will just stay dead. 😱

### Run Automatically on Startup { #run-automatically-on-startup }

In general, you will probably want the server program (e.g. Uvicorn) to be started automatically on server startup, and without needing any **human intervention**, to have a process always running with your API (e.g. Uvicorn running your FastAPI app).

### Separate Program { #separate-program }

To achieve this, you will normally have a **separate program** that would make sure your application is run on startup. And in many cases, it would also make sure other components or applications are also run, for example, a database.

### Example Tools to Run at Startup { #example-tools-to-run-at-startup }

Some examples of the tools that can do this job are:

* Docker
* Kubernetes
* Docker Compose
* Docker in Swarm Mode
* Systemd
* Supervisor
* Handled internally by a cloud provider as part of their services
* Others...

I'll give you more concrete examples in the next chapters.


docs/en/docs/deployment/concepts.md::Restarts { #restarts }::L128

# Doc: docs/en/docs/deployment/concepts.md | Page: Deployments Concepts { #deployments-concepts } | Section: Restarts { #restarts }
## Restarts { #restarts }

Similar to making sure your application is run on startup, you probably also want to make sure it is **restarted** after failures.

### We Make Mistakes { #we-make-mistakes }

We, as humans, make **mistakes**, all the time. Software almost *always* has **bugs** hidden in different places. 🐛

And we as developers keep improving the code as we find those bugs and as we implement new features (possibly adding new bugs too 😅).

### Small Errors Automatically Handled { #small-errors-automatically-handled }

When building web APIs with FastAPI, if there's an error in our code, FastAPI will normally contain it to the single request that triggered the error. 🛡

The client will get a **500 Internal Server Error** for that request, but the application will continue working for the next requests instead of just crashing completely.

### Bigger Errors - Crashes { #bigger-errors-crashes }

Nevertheless, there might be cases where we write some code that **crashes the entire application** making Uvicorn and Python crash. 💥

And still, you would probably not want the application to stay dead because there was an error in one place, you probably want it to **continue running** at least for the *path operations* that are not broken.

### Restart After Crash { #restart-after-crash }

But in those cases with really bad errors that crash the running **process**, you would want an external component that is in charge of **restarting** the process, at least a couple of times...

/// tip

...Although if the whole application is just **crashing immediately** it probably doesn't make sense to keep restarting it forever. But in those cases, you will probably notice it during development, or at least right after deployment.

So let's focus on the main cases, where it could crash entirely in some particular cases **in the future**, and it still makes sense to restart it.

///

You would probably want to have the thing in charge of restarting your application as an **external component**, because by that point, the same application with Uvicorn and Python already crashed, so there's nothing in the same code of the same app that could do anything about it.

### Example Tools to Restart Automatically { #example-tools-to-restart-automatically }

In most cases, the same tool that is used to **run the program on startup** is also used to handle automatic **restarts**.

For example, this could be handled by:

* Docker
* Kubernetes
* Docker Compose
* Docker in Swarm Mode
* Systemd
* Supervisor
* Handled internally by a cloud provider as part of their services
* Others...


docs/en/docs/deployment/concepts.md::Replication - Processes and Memory { #replication-processes-and-memory }::L179

# Doc: docs/en/docs/deployment/concepts.md | Page: Deployments Concepts { #deployments-concepts } | Section: Replication - Processes and Memory { #replication-processes-and-memory }
## Replication - Processes and Memory { #replication-processes-and-memory }

With a FastAPI application, using a server program like the `fastapi` command that runs Uvicorn, running it once in **one process** can serve multiple clients concurrently.

But in many cases, you will want to run several worker processes at the same time.

### Multiple Processes - Workers { #multiple-processes-workers }

If you have more clients than what a single process can handle (for example if the virtual machine is not too big) and you have **multiple cores** in the server's CPU, then you could have **multiple processes** running with the same application at the same time, and distribute all the requests among them.

When you run **multiple processes** of the same API program, they are commonly called **workers**.

### Worker Processes and Ports { #worker-processes-and-ports }

Remember from the docs [About HTTPS](https.md) that only one process can be listening on one combination of port and IP address in a server?

This is still true.

So, to be able to have **multiple processes** at the same time, there has to be a **single process listening on a port** that then transmits the communication to each worker process in some way.

### Memory per Process { #memory-per-process }

Now, when the program loads things in memory, for example, a machine learning model in a variable, or the contents of a large file in a variable, all that **consumes a bit of the memory (RAM)** of the server.

And multiple processes normally **don't share any memory**. This means that each running process has its own things, variables, and memory. And if you are consuming a large amount of memory in your code, **each process** will consume an equivalent amount of memory.

### Server Memory { #server-memory }

For example, if your code loads a Machine Learning model with **1 GB in size**, when you run one process with your API, it will consume at least 1 GB of RAM. And if you start **4 processes** (4 workers), each will consume 1 GB of RAM. So in total, your API will consume **4 GB of RAM**.

And if your remote server or virtual machine only has 3 GB of RAM, trying to load more than 4 GB of RAM will cause problems. 🚨

### Multiple Processes - An Example { #multiple-processes-an-example }

In this example, there's a **Manager Process** that starts and controls two **Worker Processes**.

This Manager Process would probably be the one listening on the **port** in the IP. And it would transmit all the communication to the worker processes.

Those worker processes would be the ones running your application, they would perform the main computations to receive a **request** and return a **response**, and they would load anything you put in variables in RAM.

<img src="/img/deployment/concepts/process-ram.drawio.svg">

And of course, the same machine would probably have **other processes** running as well, apart from your application.

An interesting detail is that the percentage of the **CPU used** by each process can **vary** a lot over time, but the **memory (RAM)** normally stays more or less **stable**.

If you have an API that does a comparable amount of computations every time and you have a lot of clients, then the **CPU utilization** will probably *also be stable* (instead of constantly going up and down quickly).

### Examples of Replication Tools and Strategies { #examples-of-replication-tools-and-strategies }

There can be several approaches to achieve this, and I'll tell you more about specific strategies in the next chapters, for example when talking about Docker and containers.

The main constraint to consider is that there has to be a **single** component handling the **port** in the **public IP**. And then it has to have a way to **transmit** the communication to the replicated **processes/workers**.

Here are some possible combinations and strategies:

* **Uvicorn** with `--workers`
    * One Uvicorn **process manager** would listen on the **IP** and **port**, and it would start **multiple Uvicorn worker processes**.
* **Kubernetes** and other distributed **container systems**
    * Something in the **Kubernetes** layer would listen on the **IP** and **port**. The replication would be by having **multiple containers**, each with **one Uvicorn process** running.
* **Cloud services** that handle this for you
    * The cloud service will probably **handle replication for you**. It would possibly let you define **a process to run**, or a **container image** to use, in any case, it would most probably be **a single Uvicorn process**, and the cloud service would be in charge of replicating it.

/// tip

Don't worry if some of these items about **containers**, Docker, or Kubernetes don't make a lot of sense yet.

I'll tell you more about container images, Docker, Kubernetes, etc. in a future chapter: [FastAPI in Containers - Docker](docker.md).

///


docs/en/docs/deployment/concepts.md::Previous Steps Before Starting { #previous-steps-before-starting }::L250

# Doc: docs/en/docs/deployment/concepts.md | Page: Deployments Concepts { #deployments-concepts } | Section: Previous Steps Before Starting { #previous-steps-before-starting }
## Previous Steps Before Starting { #previous-steps-before-starting }

There are many cases where you want to perform some steps **before starting** your application.

For example, you might want to run **database migrations**.

But in most cases, you will want to perform these steps only **once**.

So, you will want to have a **single process** to perform those **previous steps**, before starting the application.

And you will have to make sure that it's a single process running those previous steps *even* if afterwards, you start **multiple processes** (multiple workers) for the application itself. If those steps were run by **multiple processes**, they would **duplicate** the work by running it in **parallel**, and if the steps were something delicate like a database migration, they could cause conflicts with each other.

Of course, there are some cases where there's no problem in running the previous steps multiple times, in that case, it's a lot easier to handle.

/// tip

Also, keep in mind that depending on your setup, in some cases you **might not even need any previous steps** before starting your application.

In that case, you wouldn't have to worry about any of this. 🤷

///

### Examples of Previous Steps Strategies { #examples-of-previous-steps-strategies }

This will **depend heavily** on the way you **deploy your system**, and it would probably be connected to the way you start programs, handling restarts, etc.

Here are some possible ideas:

* An "Init Container" in Kubernetes that runs before your app container
* A bash script that runs the previous steps and then starts your application
    * You would still need a way to start/restart *that* bash script, detect errors, etc.

/// tip

I'll give you more concrete examples for doing this with containers in a future chapter: [FastAPI in Containers - Docker](docker.md).

///


docs/en/docs/deployment/concepts.md::Resource Utilization { #resource-utilization }::L288

# Doc: docs/en/docs/deployment/concepts.md | Page: Deployments Concepts { #deployments-concepts } | Section: Resource Utilization { #resource-utilization }
## Resource Utilization { #resource-utilization }

Your server(s) is (are) a **resource**, you can consume or **utilize**, with your programs, the computation time on the CPUs, and the RAM memory available.

How much of the system resources do you want to be consuming/utilizing? It might be easy to think "not much", but in reality, you will probably want to consume **as much as possible without crashing**.

If you are paying for 3 servers but you are using only a little bit of their RAM and CPU, you are probably **wasting money** 💸, and probably **wasting server electric power** 🌎, etc.

In that case, it could be better to have only 2 servers and use a higher percentage of their resources (CPU, memory, disk, network bandwidth, etc).

On the other hand, if you have 2 servers and you are using **100% of their CPU and RAM**, at some point one process will ask for more memory, and the server will have to use the disk as "memory" (which can be thousands of times slower), or even **crash**. Or one process might need to do some computation and would have to wait until the CPU is free again.

In this case, it would be better to get **one extra server** and run some processes on it so that they all have **enough RAM and CPU time**.

There's also the chance that for some reason you have a **spike** of usage of your API. Maybe it went viral, or maybe some other services or bots start using it. And you might want to have extra resources to be safe in those cases.

You could put an **arbitrary number** to target, for example, something **between 50% to 90%** of resource utilization. The point is that those are probably the main things you will want to measure and use to tweak your deployments.

You can use simple tools like `htop` to see the CPU and RAM used in your server or the amount used by each process. Or you can use more complex monitoring tools, which may be distributed across servers, etc.


docs/en/docs/deployment/concepts.md::Recap { #recap }::L308

# Doc: docs/en/docs/deployment/concepts.md | Page: Deployments Concepts { #deployments-concepts } | Section: Recap { #recap }
## Recap { #recap }

You have been reading here some of the main concepts that you would probably need to keep in mind when deciding how to deploy your application:

* Security - HTTPS
* Running on startup
* Restarts
* Replication (the number of processes running)
* Memory
* Previous steps before starting

Understanding these ideas and how to apply them should give you the intuition necessary to take any decisions when configuring and tweaking your deployments. 🤓

In the next sections, I'll give you more concrete examples of possible strategies you can follow. 🚀


docs/en/docs/deployment/docker.md::FastAPI in Containers - Docker { #fastapi-in-containers-docker }::L1

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: FastAPI in Containers - Docker { #fastapi-in-containers-docker }
# FastAPI in Containers - Docker { #fastapi-in-containers-docker }

When deploying FastAPI applications a common approach is to build a **Linux container image**. It's normally done using [**Docker**](https://www.docker.com/). You can then deploy that container image in one of a few possible ways.

Using Linux containers has several advantages including **security**, **replicability**, **simplicity**, and others.

/// tip

In a hurry and already know this stuff? Jump to the [`Dockerfile` below 👇](#build-a-docker-image-for-fastapi).

///

<details>
<summary>Dockerfile Preview 👀</summary>

```Dockerfile
FROM python:3.14

WORKDIR /code

COPY ./requirements.txt /code/requirements.txt

RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

COPY ./app /code/app

CMD ["fastapi", "run", "app/main.py", "--port", "80"]

# If running behind a proxy like Nginx or Traefik add --proxy-headers
# CMD ["fastapi", "run", "app/main.py", "--port", "80", "--proxy-headers"]
```

</details>


docs/en/docs/deployment/docker.md::What is a Container { #what-is-a-container }::L35

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: What is a Container { #what-is-a-container }
## What is a Container { #what-is-a-container }

Containers (mainly Linux containers) are a very **lightweight** way to package applications including all their dependencies and necessary files while keeping them isolated from other containers (other applications or components) in the same system.

Linux containers run using the same Linux kernel of the host (machine, virtual machine, cloud server, etc). This just means that they are very lightweight (compared to full virtual machines emulating an entire operating system).

This way, containers consume **little resources**, an amount comparable to running the processes directly (a virtual machine would consume much more).

Containers also have their own **isolated** running processes (commonly just one process), file system, and network, simplifying deployment, security, development, etc.


docs/en/docs/deployment/docker.md::What is a Container Image { #what-is-a-container-image }::L45

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: What is a Container Image { #what-is-a-container-image }
## What is a Container Image { #what-is-a-container-image }

A **container** is run from a **container image**.

A container image is a **static** version of all the files, environment variables, and the default command/program that should be present in a container. **Static** here means that the container **image** is not running, it's not being executed, it's only the packaged files and metadata.

In contrast to a "**container image**" that is the stored static contents, a "**container**" normally refers to the running instance, the thing that is being **executed**.

When the **container** is started and running (started from a **container image**) it could create or change files, environment variables, etc. Those changes will exist only in that container, but would not persist in the underlying container image (would not be saved to disk).

A container image is comparable to the **program** file and contents, e.g. `python` and some file `main.py`.

And the **container** itself (in contrast to the **container image**) is the actual running instance of the image, comparable to a **process**. In fact, a container is running only when it has a **process running** (and normally it's only a single process). The container stops when there's no process running in it.


docs/en/docs/deployment/docker.md::Container Images { #container-images }::L59

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Container Images { #container-images }
## Container Images { #container-images }

Docker has been one of the main tools to create and manage **container images** and **containers**.

And there's a public [Docker Hub](https://hub.docker.com/) with pre-made **official container images** for many tools, environments, databases, and applications.

For example, there's an official [Python Image](https://hub.docker.com/_/python).

And there are many other images for different things like databases, for example for:

* [PostgreSQL](https://hub.docker.com/_/postgres)
* [MySQL](https://hub.docker.com/_/mysql)
* [MongoDB](https://hub.docker.com/_/mongo)
* [Redis](https://hub.docker.com/_/redis), etc.

By using a pre-made container image it's very easy to **combine** and use different tools. For example, to try out a new database. In most cases, you can use the **official images**, and just configure them with environment variables.

That way, in many cases you can learn about containers and Docker and reuse that knowledge with many different tools and components.

So, you would run **multiple containers** with different things, like a database, a Python application, a web server with a React frontend application, and connect them together via their internal network.

All the container management systems (like Docker or Kubernetes) have these networking features integrated into them.


docs/en/docs/deployment/docker.md::Containers and Processes { #containers-and-processes }::L82

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Containers and Processes { #containers-and-processes }
## Containers and Processes { #containers-and-processes }

A **container image** normally includes in its metadata the default program or command that should be run when the **container** is started and the parameters to be passed to that program. Very similar to what would be if it was in the command line.

When a **container** is started, it will run that command/program (although you can override it and make it run a different command/program).

A container is running as long as the **main process** (command or program) is running.

A container normally has a **single process**, but it's also possible to start subprocesses from the main process, and that way you will have **multiple processes** in the same container.

But it's not possible to have a running container without **at least one running process**. If the main process stops, the container stops.


docs/en/docs/deployment/docker.md::Build a Docker Image for FastAPI { #build-a-docker-image-for-fastapi }::L94

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Build a Docker Image for FastAPI { #build-a-docker-image-for-fastapi }
## Build a Docker Image for FastAPI { #build-a-docker-image-for-fastapi }

Okay, let's build something now! 🚀

I'll show you how to build a **Docker image** for FastAPI **from scratch**, based on the **official Python** image.

This is what you would want to do in **most cases**, for example:

* Using **Kubernetes** or similar tools
* When running on a **Raspberry Pi**
* Using a cloud service that would run a container image for you, etc.

### Package Requirements { #package-requirements }

You would normally have the **package requirements** for your application in some file.

It would depend mainly on the tool you use to **install** those requirements.

The most common way to do it is to have a file `requirements.txt` with the package names and their versions, one per line.

You would of course use the same ideas you read in [About FastAPI versions](versions.md) to set the ranges of versions.

For example, your `requirements.txt` could look like:

```
fastapi[standard]>=0.113.0,<0.114.0
pydantic>=2.7.0,<3.0.0
```

And you would normally install those package dependencies with `pip`, for example:

```console
$ pip install -r requirements.txt
---> 100%
Successfully installed fastapi pydantic
```

/// note

There are other formats and tools to define and install package dependencies.

///

### Create the **FastAPI** Code { #create-the-fastapi-code }

* Create an `app` directory and enter it.
* Create an empty file `__init__.py`.
* Create a `main.py` file with:

```Python
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
    return {"item_id": item_id, "q": q}
```

### Dockerfile { #dockerfile }

Now in the same project directory create a file `Dockerfile` with:

```{ .dockerfile .annotate }
# (1)!
FROM python:3.14

# (2)!
WORKDIR /code

# (3)!
COPY ./requirements.txt /code/requirements.txt

# (4)!
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

# (5)!
COPY ./app /code/app

# (6)!
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
```

1. Start from the official Python base image.

2. Set the current working directory to `/code`.

    This is where we'll put the `requirements.txt` file and the `app` directory.

3. Copy the file with the requirements to the `/code` directory.

    Copy **only** the file with the requirements first, not the rest of the code.

    As this file **doesn't change often**, Docker will detect it and use the **cache** for this step, enabling the cache for the next step too.

4. Install the package dependencies in the requirements file.

    The `--no-cache-dir` option tells `pip` to not save the downloaded packages locally, as that is only if `pip` was going to be run again to install the same packages, but that's not the case when working with containers.

    /// note

    The `--no-cache-dir` is only related to `pip`, it has nothing to do with Docker or containers.

    ///

    The `--upgrade` option tells `pip` to upgrade the packages if they are already installed.

    Because the previous step copying the file could be detected by the **Docker cache**, this step will also **use the Docker cache** when available.

    Using the cache in this step will **save** you a lot of **time** when building the image again and again during development, instead of **downloading and installing** all the dependencies **every time**.

5. Copy the `./app` directory inside the `/code` directory.

    As this has all the code which is what **changes most frequently** the Docker **cache** won't be used for this or any **following steps** easily.

    So, it's important to put this **near the end** of the `Dockerfile`, to optimize the container image build times.

6. Set the **command** to use `fastapi run`, which uses Uvicorn underneath.

    `CMD` takes a list of strings, each of these strings is what you would type in the command line separated by spaces.

    This command will be run from the **current working directory**, the same `/code` directory you set above with `WORKDIR /code`.

/// tip

Review what each line does by clicking each number bubble in the code. 👆

///

/// warning

Make sure to **always** use the **exec form** of the `CMD` instruction, as explained below.

///

#### Use `CMD` - Exec Form { #use-cmd-exec-form }

The [`CMD`](https://docs.docker.com/reference/dockerfile/#cmd) Docker instruction can be written using two forms:

✅ **Exec** form:

```Dockerfile
# ✅ Do this
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
```

⛔ **Shell** form:

```Dockerfile
# ⛔ Don't do this
CMD fastapi run app/main.py --port 80
```

Make sure to always use the **exec** form to ensure that FastAPI can shutdown gracefully and [lifespan events](../advanced/events.md) are triggered.

You can read more about it in the [Docker docs for shell and exec form](https://docs.docker.com/reference/dockerfile/#shell-and-exec-form).

This can be quite noticeable when using `docker compose`. See this Docker Compose FAQ section for more technical details: [Why do my services take 10 seconds to recreate or stop?](https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop).

#### Directory Structure { #directory-structure }

You should now have a directory structure like:

```
.
├── app
│   ├── __init__.py
│   └── main.py
├── Dockerfile
└── requirements.txt
```

#### Behind a TLS Termination Proxy { #behind-a-tls-termination-proxy }

If you are running your container behind a TLS Termination Proxy (load balancer) like Nginx or Traefik, add the option `--proxy-headers`, this will tell Uvicorn (through the FastAPI CLI) to trust the headers sent by that proxy telling it that the application is running behind HTTPS, etc.

```Dockerfile
CMD ["fastapi", "run", "app/main.py", "--proxy-headers", "--port", "80"]
```

#### Docker Cache { #docker-cache }

There's an important trick in this `Dockerfile`, we first copy the **file with the dependencies alone**, not the rest of the code. Let me tell you why that is.

```Dockerfile
COPY ./requirements.txt /code/requirements.txt
```

Docker and other tools **build** these container images **incrementally**, adding **one layer on top of the other**, starting from the top of the `Dockerfile` and adding any files created by each of the instructions of the `Dockerfile`.

Docker and similar tools also use an **internal cache** when building the image, if a file hasn't changed since the last time building the container image, then it will **reuse the same layer** created the last time, instead of copying the file again and creating a new layer from scratch.

Just avoiding the copy of files doesn't necessarily improve things too much, but because it used the cache for that step, it can **use the cache for the next step**. For example, it could use the cache for the instruction that installs dependencies with:

```Dockerfile
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
```

The file with the package requirements **won't change frequently**. So, by copying only that file, Docker will be able to **use the cache** for that step.

And then, Docker will be able to **use the cache for the next step** that downloads and installs those dependencies. And here's where we **save a lot of time**. ✨ ...and avoid boredom waiting. 😪😆

Downloading and installing the package dependencies **could take minutes**, but using the **cache** would **take seconds** at most.

And as you would be building the container image again and again during development to check that your code changes are working, there's a lot of accumulated time this would save.

Then, near the end of the `Dockerfile`, we copy all the code. As this is what **changes most frequently**, we put it near the end, because almost always, anything after this step will not be able to use the cache.

```Dockerfile
COPY ./app /code/app
```

### Build the Docker Image { #build-the-docker-image }

Now that all the files are in place, let's build the container image.

* Go to the project directory (in where your `Dockerfile` is, containing your `app` directory).
* Build your FastAPI image:

```console
$ docker build -t myimage .

---> 100%
```

/// tip

Notice the `.` at the end, it's equivalent to `./`, it tells Docker the directory to use to build the container image.

In this case, it's the same current directory (`.`).

///

### Start the Docker Container { #start-the-docker-container }

* Run a container based on your image:

```console
$ docker run -d --name mycontainer -p 80:80 myimage
```


docs/en/docs/deployment/docker.md::Check it { #check-it }::L353

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Check it { #check-it }
## Check it { #check-it }

You should be able to check it in your Docker container's URL, for example: [http://192.168.99.100/items/5?q=somequery](http://192.168.99.100/items/5?q=somequery) or [http://127.0.0.1/items/5?q=somequery](http://127.0.0.1/items/5?q=somequery) (or equivalent, using your Docker host).

You will see something like:

```JSON
{"item_id": 5, "q": "somequery"}
```


docs/en/docs/deployment/docker.md::Interactive API docs { #interactive-api-docs }::L363

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Interactive API docs { #interactive-api-docs }
## Interactive API docs { #interactive-api-docs }

Now you can go to [http://192.168.99.100/docs](http://192.168.99.100/docs) or [http://127.0.0.1/docs](http://127.0.0.1/docs) (or equivalent, using your Docker host).

You will see the automatic interactive API documentation (provided by [Swagger UI](https://github.com/swagger-api/swagger-ui)):

![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)


docs/en/docs/deployment/docker.md::Alternative API docs { #alternative-api-docs }::L371

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Alternative API docs { #alternative-api-docs }
## Alternative API docs { #alternative-api-docs }

And you can also go to [http://192.168.99.100/redoc](http://192.168.99.100/redoc) or [http://127.0.0.1/redoc](http://127.0.0.1/redoc) (or equivalent, using your Docker host).

You will see the alternative automatic documentation (provided by [ReDoc](https://github.com/Rebilly/ReDoc)):

![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)


docs/en/docs/deployment/docker.md::Build a Docker Image with a Single-File FastAPI { #build-a-docker-image-with-a-single-file-fastapi }::L379

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Build a Docker Image with a Single-File FastAPI { #build-a-docker-image-with-a-single-file-fastapi }
## Build a Docker Image with a Single-File FastAPI { #build-a-docker-image-with-a-single-file-fastapi }

If your FastAPI is a single file, for example, `main.py` without an `./app` directory, your file structure could look like this:

```
.
├── Dockerfile
├── main.py
└── requirements.txt
```

Then you would just have to change the corresponding paths to copy the file inside the `Dockerfile`:

```{ .dockerfile .annotate hl_lines="10  13" }
FROM python:3.14

WORKDIR /code

COPY ./requirements.txt /code/requirements.txt

RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

# (1)!
COPY ./main.py /code/

# (2)!
CMD ["fastapi", "run", "main.py", "--port", "80"]
```

1. Copy the `main.py` file to the `/code` directory directly (without any `./app` directory).

2. Use `fastapi run` to serve your application in the single file `main.py`.

When you pass the file to `fastapi run` it will detect automatically that it is a single file and not part of a package and will know how to import it and serve your FastAPI app. 😎


docs/en/docs/deployment/docker.md::Deployment Concepts { #deployment-concepts }::L414

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Deployment Concepts { #deployment-concepts }
## Deployment Concepts { #deployment-concepts }

Let's talk again about some of the same [Deployment Concepts](concepts.md) in terms of containers.

Containers are mainly a tool to simplify the process of **building and deploying** an application, but they don't enforce a particular approach to handle these **deployment concepts**, and there are several possible strategies.

The **good news** is that with each different strategy there's a way to cover all of the deployment concepts. 🎉

Let's review these **deployment concepts** in terms of containers:

* HTTPS
* Running on startup
* Restarts
* Replication (the number of processes running)
* Memory
* Previous steps before starting


docs/en/docs/deployment/docker.md::HTTPS { #https }::L431

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: HTTPS { #https }
## HTTPS { #https }

If we focus just on the **container image** for a FastAPI application (and later the running **container**), HTTPS normally would be handled **externally** by another tool.

It could be another container, for example with [Traefik](https://traefik.io/), handling **HTTPS** and **automatic** acquisition of **certificates**.

/// tip

Traefik has integrations with Docker, Kubernetes, and others, so it's very easy to set up and configure HTTPS for your containers with it.

///

Alternatively, HTTPS could be handled by a cloud provider as one of their services (while still running the application in a container).


docs/en/docs/deployment/docker.md::Running on Startup and Restarts { #running-on-startup-and-restarts }::L445

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Running on Startup and Restarts { #running-on-startup-and-restarts }
## Running on Startup and Restarts { #running-on-startup-and-restarts }

There is normally another tool in charge of **starting and running** your container.

It could be **Docker** directly, **Docker Compose**, **Kubernetes**, a **cloud service**, etc.

In most (or all) cases, there's a simple option to enable running the container on startup and enabling restarts on failures. For example, in Docker, it's the command line option `--restart`.

Without using containers, making applications run on startup and with restarts can be cumbersome and difficult. But when **working with containers** in most cases that functionality is included by default. ✨


docs/en/docs/deployment/docker.md::Replication - Number of Processes { #replication-number-of-processes }::L455

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Replication - Number of Processes { #replication-number-of-processes }
## Replication - Number of Processes { #replication-number-of-processes }

If you have a <dfn title="A group of machines that are configured to be connected and work together in some way.">cluster</dfn> of machines with **Kubernetes**, Docker Swarm Mode, Nomad, or another similar complex system to manage distributed containers on multiple machines, then you will probably want to **handle replication** at the **cluster level** instead of using a **process manager** (like Uvicorn with workers) in each container.

One of those distributed container management systems like Kubernetes normally has some integrated way of handling **replication of containers** while still supporting **load balancing** for the incoming requests. All at the **cluster level**.

In those cases, you would probably want to build a **Docker image from scratch** as [explained above](#dockerfile), installing your dependencies, and running **a single Uvicorn process** instead of using multiple Uvicorn workers.

### Load Balancer { #load-balancer }

When using containers, you would normally have some component **listening on the main port**. It could possibly be another container that is also a **TLS Termination Proxy** to handle **HTTPS** or some similar tool.

As this component would take the **load** of requests and distribute that among the workers in a (hopefully) **balanced** way, it is also commonly called a **Load Balancer**.

/// tip

The same **TLS Termination Proxy** component used for HTTPS would probably also be a **Load Balancer**.

///

And when working with containers, the same system you use to start and manage them would already have internal tools to transmit the **network communication** (e.g. HTTP requests) from that **load balancer** (that could also be a **TLS Termination Proxy**) to the container(s) with your app.

### One Load Balancer - Multiple Worker Containers { #one-load-balancer-multiple-worker-containers }

When working with **Kubernetes** or similar distributed container management systems, using their internal networking mechanisms would allow the single **load balancer** that is listening on the main **port** to transmit communication (requests) to possibly **multiple containers** running your app.

Each of these containers running your app would normally have **just one process** (e.g. a Uvicorn process running your FastAPI application). They would all be **identical containers**, running the same thing, but each with its own process, memory, etc. That way you would take advantage of **parallelization** in **different cores** of the CPU, or even in **different machines**.

And the distributed container system with the **load balancer** would **distribute the requests** to each one of the containers with your app **in turns**. So, each request could be handled by one of the multiple **replicated containers** running your app.

And normally this **load balancer** would be able to handle requests that go to *other* apps in your cluster (e.g. to a different domain, or under a different URL path prefix), and would transmit that communication to the right containers for *that other* application running in your cluster.

### One Process per Container { #one-process-per-container }

In this type of scenario, you probably would want to have **a single (Uvicorn) process per container**, as you would already be handling replication at the cluster level.

So, in this case, you **would not** want to have multiple workers in the container, for example with the `--workers` command line option. You would want to have just a **single Uvicorn process** per container (but probably multiple containers).

Having another process manager inside the container (as would be with multiple workers) would only add **unnecessary complexity** that you are most probably already taking care of with your cluster system.

### Containers with Multiple Processes and Special Cases { #containers-with-multiple-processes-and-special-cases }

Of course, there are **special cases** where you could want to have **a container** with several **Uvicorn worker processes** inside.

In those cases, you can use the `--workers` command line option to set the number of workers that you want to run:

```{ .dockerfile .annotate }
FROM python:3.14

WORKDIR /code

COPY ./requirements.txt /code/requirements.txt

RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

COPY ./app /code/app

# (1)!
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]
```

1. Here we use the `--workers` command line option to set the number of workers to 4.

Here are some examples of when that could make sense:

#### A Simple App { #a-simple-app }

You could want a process manager in the container if your application is **simple enough** that you can run it on a **single server**, not a cluster.

#### Docker Compose { #docker-compose }

You could be deploying to a **single server** (not a cluster) with **Docker Compose**, so you wouldn't have an easy way to manage replication of containers (with Docker Compose) while preserving the shared network and **load balancing**.

Then you could want to have **a single container** with a **process manager** starting **several worker processes** inside.

---

The main point is, **none** of these are **rules written in stone** that you have to blindly follow. You can use these ideas to **evaluate your own use case** and decide what is the best approach for your system, checking out how to manage the concepts of:

* Security - HTTPS
* Running on startup
* Restarts
* Replication (the number of processes running)
* Memory
* Previous steps before starting


docs/en/docs/deployment/docker.md::Memory { #memory }::L541

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Memory { #memory }
## Memory { #memory }

If you run **a single process per container** you will have a more or less well-defined, stable, and limited amount of memory consumed by each of those containers (more than one if they are replicated).

And then you can set those same memory limits and requirements in your configurations for your container management system (for example in **Kubernetes**). That way it will be able to **replicate the containers** in the **available machines** taking into account the amount of memory needed by them, and the amount available in the machines in the cluster.

If your application is **simple**, this will probably **not be a problem**, and you might not need to specify hard memory limits. But if you are **using a lot of memory** (for example with **machine learning** models), you should check how much memory you are consuming and adjust the **number of containers** that run on **each machine** (and maybe add more machines to your cluster).

If you run **multiple processes per container** you will have to make sure that the number of processes started doesn't **consume more memory** than what is available.


docs/en/docs/deployment/docker.md::Previous Steps Before Starting and Containers { #previous-steps-before-starting-and-containers }::L551

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Previous Steps Before Starting and Containers { #previous-steps-before-starting-and-containers }
## Previous Steps Before Starting and Containers { #previous-steps-before-starting-and-containers }

If you are using containers (e.g. Docker, Kubernetes), then there are two main approaches you can use.

### Multiple Containers { #multiple-containers }

If you have **multiple containers**, probably each one running a **single process** (for example, in a **Kubernetes** cluster), then you would probably want to have a **separate container** doing the work of the **previous steps** in a single container, running a single process, **before** running the replicated worker containers.

/// note

If you are using Kubernetes, this would probably be an [Init Container](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/).

///

If in your use case there's no problem in running those previous steps **multiple times in parallel** (for example if you are not running database migrations, but just checking if the database is ready yet), then you could also just put them in each container right before starting the main process.

### Single Container { #single-container }

If you have a simple setup, with a **single container** that then starts multiple **worker processes** (or also just one process), then you could run those previous steps in the same container, right before starting the process with the app.

### Base Docker Image { #base-docker-image }

There used to be an official FastAPI Docker image: [tiangolo/uvicorn-gunicorn-fastapi](https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker). But it is now deprecated. ⛔

You should probably **not** use this base Docker image (or any other similar one).

If you are using **Kubernetes** (or others) and you are already setting **replication** at the cluster level, with multiple **containers**. In those cases, you are better off **building an image from scratch** as described above: [Build a Docker Image for FastAPI](#build-a-docker-image-for-fastapi).

And if you need to have multiple workers, you can simply use the `--workers` command line option.

/// note | Technical Details

The Docker image was created when Uvicorn didn't support managing and restarting dead workers, so it was needed to use Gunicorn with Uvicorn, which added quite some complexity, just to have Gunicorn manage and restart the Uvicorn worker processes.

But now that Uvicorn (and the `fastapi` command) support using `--workers`, there's no reason to use a base Docker image instead of building your own (it's pretty much the same amount of code 😅).

///


docs/en/docs/deployment/docker.md::Deploy the Container Image { #deploy-the-container-image }::L589

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Deploy the Container Image { #deploy-the-container-image }
## Deploy the Container Image { #deploy-the-container-image }

After having a Container (Docker) Image there are several ways to deploy it.

For example:

* With **Docker Compose** in a single server
* With a **Kubernetes** cluster
* With a Docker Swarm Mode cluster
* With another tool like Nomad
* With a cloud service that takes your container image and deploys it


docs/en/docs/deployment/docker.md::Docker Image with `uv` { #docker-image-with-uv }::L601

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Docker Image with `uv` { #docker-image-with-uv }
## Docker Image with `uv` { #docker-image-with-uv }

If you are using [uv](https://github.com/astral-sh/uv) to install and manage your project, you can follow their [uv Docker guide](https://docs.astral.sh/uv/guides/integration/docker/).


docs/en/docs/deployment/docker.md::Recap { #recap }::L605

# Doc: docs/en/docs/deployment/docker.md | Page: FastAPI in Containers - Docker { #fastapi-in-containers-docker } | Section: Recap { #recap }
## Recap { #recap }

Using container systems (e.g. with **Docker** and **Kubernetes**) it becomes fairly straightforward to handle all the **deployment concepts**:

* HTTPS
* Running on startup
* Restarts
* Replication (the number of processes running)
* Memory
* Previous steps before starting

In most cases, you probably won't want to use any base image, and instead **build a container image from scratch** based on the official Python Docker image.

Taking care of the **order** of instructions in the `Dockerfile` and the **Docker cache** you can **minimize build times**, to maximize your productivity (and avoid boredom). 😎


docs/en/docs/deployment/fastapicloud.md::FastAPI Cloud { #fastapi-cloud }::L1

# Doc: docs/en/docs/deployment/fastapicloud.md | Page: FastAPI Cloud { #fastapi-cloud } | Section: FastAPI Cloud { #fastapi-cloud }
# FastAPI Cloud { #fastapi-cloud }

You can deploy your FastAPI app to [FastAPI Cloud](https://fastapicloud.com) with just **one command**. 🚀

<div class="termy">

```console
$ fastapi deploy

Deploying to FastAPI Cloud...

✅ Deployment successful!

🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev
```

</div>

The CLI will automatically detect your FastAPI application and deploy it to the cloud. If you are not logged in, your browser will open to complete the authentication process.

That's it! Now you can access your app at that URL. ✨


docs/en/docs/deployment/fastapicloud.md::About FastAPI Cloud { #about-fastapi-cloud }::L23

# Doc: docs/en/docs/deployment/fastapicloud.md | Page: FastAPI Cloud { #fastapi-cloud } | Section: About FastAPI Cloud { #about-fastapi-cloud }
## About FastAPI Cloud { #about-fastapi-cloud }

**[FastAPI Cloud](https://fastapicloud.com)** is built by the same author and team behind **FastAPI**.

It streamlines the process of **building**, **deploying**, and **accessing** an API with minimal effort.

It brings the same **developer experience** of building apps with FastAPI to **deploying** them to the cloud. 🎉

It will also take care of most of the things you would need when deploying an app, like:

* HTTPS
* Replication, with autoscaling based on requests
* etc.

FastAPI Cloud is the primary sponsor and funding provider for the *FastAPI and friends* open source projects. ✨


docs/en/docs/deployment/fastapicloud.md::Deploy to other cloud providers { #deploy-to-other-cloud-providers }::L39

# Doc: docs/en/docs/deployment/fastapicloud.md | Page: FastAPI Cloud { #fastapi-cloud } | Section: Deploy to other cloud providers { #deploy-to-other-cloud-providers }
## Deploy to other cloud providers { #deploy-to-other-cloud-providers }

FastAPI is open source and based on standards. You can deploy FastAPI apps to any cloud provider you choose.

Follow your cloud provider's guides to deploy FastAPI apps with them. 🤓


docs/en/docs/deployment/fastapicloud.md::Deploy your own server { #deploy-your-own-server }::L45

# Doc: docs/en/docs/deployment/fastapicloud.md | Page: FastAPI Cloud { #fastapi-cloud } | Section: Deploy your own server { #deploy-your-own-server }
## Deploy your own server { #deploy-your-own-server }

I will also teach you later in this **Deployment** guide all the details, so you can understand what is going on, what needs to happen, or how to deploy FastAPI apps on your own, also with your own servers. 🤓


docs/en/docs/deployment/https.md::About HTTPS { #about-https }::L1

# Doc: docs/en/docs/deployment/https.md | Page: About HTTPS { #about-https } | Section: About HTTPS { #about-https }
# About HTTPS { #about-https }

It is easy to assume that HTTPS is something that is just "enabled" or not.

But it is way more complex than that.

/// tip

If you are in a hurry or don't care, continue with the next sections for step by step instructions to set everything up with different techniques.

///

To **learn the basics of HTTPS**, from a consumer perspective, check [https://howhttps.works/](https://howhttps.works/).

Now, from a **developer's perspective**, here are several things to keep in mind while thinking about HTTPS:

* For HTTPS, **the server** needs to **have "certificates"** generated by a **third party**.
    * Those certificates are actually **acquired** from the third party, not "generated".
* Certificates have a **lifetime**.
    * They **expire**.
    * And then they need to be **renewed**, **acquired again** from the third party.
* The encryption of the connection happens at the **TCP level**.
    * That's one layer **below HTTP**.
    * So, the **certificate and encryption** handling is done **before HTTP**.
* **TCP doesn't know about "domains"**. Only about IP addresses.
    * The information about the **specific domain** requested goes in the **HTTP data**.
* The **HTTPS certificates** "certify" a **certain domain**, but the protocol and encryption happen at the TCP level, **before knowing** which domain is being dealt with.
* **By default**, that would mean that you can only have **one HTTPS certificate per IP address**.
    * No matter how big your server is or how small each application you have on it might be.
    * There is a **solution** to this, however.
* There's an **extension** to the **TLS** protocol (the one handling the encryption at the TCP level, before HTTP) called **[<abbr title="Server Name Indication">SNI</abbr>](https://en.wikipedia.org/wiki/Server_Name_Indication)**.
    * This SNI extension allows one single server (with a **single IP address**) to have **several HTTPS certificates** and serve **multiple HTTPS domains/applications**.
    * For this to work, a **single** component (program) running on the server, listening on the **public IP address**, must have **all the HTTPS certificates** in the server.
* **After** obtaining a secure connection, the communication protocol is **still HTTP**.
    * The contents are **encrypted**, even though they are being sent with the **HTTP protocol**.

It is a common practice to have **one program/HTTP server** running on the server (the machine, host, etc.) and **managing all the HTTPS parts**: receiving the **encrypted HTTPS requests**, sending the **decrypted HTTP requests** to the actual HTTP application running in the same server (the **FastAPI** application, in this case), take the **HTTP response** from the application, **encrypt it** using the appropriate **HTTPS certificate** and sending it back to the client using **HTTPS**. This server is often called a **[TLS Termination Proxy](https://en.wikipedia.org/wiki/TLS_termination_proxy)**.

Some of the options you could use as a TLS Termination Proxy are:

* Traefik (that can also handle certificate renewals)
* Caddy (that can also handle certificate renewals)
* Nginx
* HAProxy


docs/en/docs/deployment/https.md::Let's Encrypt { #lets-encrypt }::L46

# Doc: docs/en/docs/deployment/https.md | Page: About HTTPS { #about-https } | Section: Let's Encrypt { #lets-encrypt }
## Let's Encrypt { #lets-encrypt }

Before Let's Encrypt, these **HTTPS certificates** were sold by trusted third parties.

The process to acquire one of these certificates used to be cumbersome, require quite some paperwork and the certificates were quite expensive.

But then **[Let's Encrypt](https://letsencrypt.org/)** was created.

It is a project from the Linux Foundation. It provides **HTTPS certificates for free**, in an automated way. These certificates use all the standard cryptographic security, and are short-lived (about 3 months), so the **security is actually better** because of their reduced lifespan.

The domains are securely verified and the certificates are generated automatically. This also allows automating the renewal of these certificates.

The idea is to automate the acquisition and renewal of these certificates so that you can have **secure HTTPS, for free, forever**.


docs/en/docs/deployment/https.md::HTTPS for Developers { #https-for-developers }::L60

# Doc: docs/en/docs/deployment/https.md | Page: About HTTPS { #about-https } | Section: HTTPS for Developers { #https-for-developers }
## HTTPS for Developers { #https-for-developers }

Here's an example of how an HTTPS API could look, step by step, paying attention mainly to the ideas important for developers.

### Domain Name { #domain-name }

It would probably all start by you **acquiring** some **domain name**. Then, you would configure it in a DNS server (possibly your same cloud provider).

You would probably get a cloud server (a virtual machine) or something similar, and it would have a <dfn title="Doesn't change over time. Not dynamic.">fixed</dfn> **public IP address**.

In the DNS server(s) you would configure a record (an "`A record`") to point **your domain** to the public **IP address of your server**.

You would probably do this just once, the first time, when setting everything up.

/// tip

This Domain Name part is way before HTTPS, but as everything depends on the domain and the IP address, it's worth mentioning it here.

///

### DNS { #dns }

Now let's focus on all the actual HTTPS parts.

First, the browser would check with the **DNS servers** what is the **IP for the domain**, in this case, `someapp.example.com`.

The DNS servers would tell the browser to use some specific **IP address**. That would be the public IP address used by your server, that you configured in the DNS servers.

### TLS Handshake Start { #tls-handshake-start }

The browser would then communicate with that IP address on **port 443** (the HTTPS port).

The first part of the communication is just to establish the connection between the client and the server and to decide the cryptographic keys they will use, etc.

This interaction between the client and the server to establish the TLS connection is called the **TLS handshake**.

### TLS with SNI Extension { #tls-with-sni-extension }

**Only one process** in the server can be listening on a specific **port** in a specific **IP address**. There could be other processes listening on other ports in the same IP address, but only one for each combination of IP address and port.

TLS (HTTPS) uses the specific port `443` by default. So that's the port we would need.

As only one process can be listening on this port, the process that would do it would be the **TLS Termination Proxy**.

The TLS Termination Proxy would have access to one or more **TLS certificates** (HTTPS certificates).

Using the **SNI extension** discussed above, the TLS Termination Proxy would check which of the TLS (HTTPS) certificates available it should use for this connection, using the one that matches the domain expected by the client.

In this case, it would use the certificate for `someapp.example.com`.

The client already **trusts** the entity that generated that TLS certificate (in this case Let's Encrypt, but we'll see about that later), so it can **verify** that the certificate is valid.

Then, using the certificate, the client and the TLS Termination Proxy **decide how to encrypt** the rest of the **TCP communication**. This completes the **TLS Handshake** part.

After this, the client and the server have an **encrypted TCP connection**, this is what TLS provides. And then they can use that connection to start the actual **HTTP communication**.

And that's what **HTTPS** is, it's just plain **HTTP** inside a **secure TLS connection** instead of a pure (unencrypted) TCP connection.

/// tip

Notice that the encryption of the communication happens at the **TCP level**, not at the HTTP level.

///

### HTTPS Request { #https-request }

Now that the client and server (specifically the browser and the TLS Termination Proxy) have an **encrypted TCP connection**, they can start the **HTTP communication**.

So, the client sends an **HTTPS request**. This is just an HTTP request through an encrypted TLS connection.

### Decrypt the Request { #decrypt-the-request }

The TLS Termination Proxy would use the encryption agreed to **decrypt the request**, and would transmit the **plain (decrypted) HTTP request** to the process running the application (for example a process with Uvicorn running the FastAPI application).

### HTTP Response { #http-response }

The application would process the request and send a **plain (unencrypted) HTTP response** to the TLS Termination Proxy.

### HTTPS Response { #https-response }

The TLS Termination Proxy would then **encrypt the response** using the cryptography agreed before (that started with the certificate for `someapp.example.com`), and send it back to the browser.

Next, the browser would verify that the response is valid and encrypted with the right cryptographic key, etc. It would then **decrypt the response** and process it.

The client (browser) will know that the response comes from the correct server because it is using the cryptography they agreed using the **HTTPS certificate** before.

### Multiple Applications { #multiple-applications }

In the same server (or servers), there could be **multiple applications**, for example, other API programs or a database.

Only one process can be handling the specific IP and port (the TLS Termination Proxy in our example) but the other applications/processes can be running on the server(s) too, as long as they don't try to use the same **combination of public IP and port**.

That way, the TLS Termination Proxy could handle HTTPS and certificates for **multiple domains**, for multiple applications, and then transmit the requests to the right application in each case.

### Certificate Renewal { #certificate-renewal }

At some point in the future, each certificate would **expire** (about 3 months after acquiring it).

And then, there would be another program (in some cases it's another program, in some cases it could be the same TLS Termination Proxy) that would talk to Let's Encrypt, and renew the certificate(s).

The **TLS certificates** are **associated with a domain name**, not with an IP address.

So, to renew the certificates, the renewal program needs to **prove** to the authority (Let's Encrypt) that it indeed **"owns" and controls that domain**.

To do that, and to accommodate different application needs, there are several ways it can do it. Some popular ways are:

* **Modify some DNS records**.
    * For this, the renewal program needs to support the APIs of the DNS provider, so, depending on the DNS provider you are using, this might or might not be an option.
* **Run as a server** (at least during the certificate acquisition process) on the public IP address associated with the domain.
    * As we said above, only one process can be listening on a specific IP and port.
    * This is one of the reasons why it's very useful when the same TLS Termination Proxy also takes care of the certificate renewal process.
    * Otherwise, you might have to stop the TLS Termination Proxy momentarily, start the renewal program to acquire the certificates, then configure them with the TLS Termination Proxy, and then restart the TLS Termination Proxy. This is not ideal, as your app(s) will not be available during the time that the TLS Termination Proxy is off.

All this renewal process, while still serving the app, is one of the main reasons why you would want to have a **separate system to handle HTTPS** with a TLS Termination Proxy instead of just using the TLS certificates with the application server directly (e.g. Uvicorn).


docs/en/docs/deployment/https.md::Proxy Forwarded Headers { #proxy-forwarded-headers }::L193

# Doc: docs/en/docs/deployment/https.md | Page: About HTTPS { #about-https } | Section: Proxy Forwarded Headers { #proxy-forwarded-headers }
## Proxy Forwarded Headers { #proxy-forwarded-headers }

When using a proxy to handle HTTPS, your **application server** (for example Uvicorn via FastAPI CLI) doesn't know anything about the HTTPS process, it communicates with plain HTTP with the **TLS Termination Proxy**.

This **proxy** would normally set some HTTP headers on the fly before transmitting the request to the **application server**, to let the application server know that the request is being **forwarded** by the proxy.

/// note | Technical Details

The proxy headers are:

* [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-For)
* [X-Forwarded-Proto](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Proto)
* [X-Forwarded-Host](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Forwarded-Host)

///

Nevertheless, as the **application server** doesn't know it is behind a trusted **proxy**, by default, it wouldn't trust those headers.

But you can configure the **application server** to trust the *forwarded* headers sent by the **proxy**. If you are using FastAPI CLI, you can use the *CLI Option* `--forwarded-allow-ips` to tell it from which IPs it should trust those *forwarded* headers.

For example, if the **application server** is only receiving communication from the trusted **proxy**, you can set it to `--forwarded-allow-ips="*"` to make it trust all incoming IPs, as it will only receive requests from whatever is the IP used by the **proxy**.

This way the application would be able to know what is its own public URL, if it is using HTTPS, the domain, etc.

This would be useful for example to properly handle redirects.

/// tip

You can learn more about this in the documentation for [Behind a Proxy - Enable Proxy Forwarded Headers](../advanced/behind-a-proxy.md#enable-proxy-forwarded-headers)

///


docs/en/docs/deployment/https.md::Recap { #recap }::L225

# Doc: docs/en/docs/deployment/https.md | Page: About HTTPS { #about-https } | Section: Recap { #recap }
## Recap { #recap }

Having **HTTPS** is very important, and quite **critical** in most cases. Most of the effort you as a developer have to put around HTTPS is just about **understanding these concepts** and how they work.

But once you know the basic information of **HTTPS for developers** you can easily combine and configure different tools to help you manage everything in a simple way.

In some of the next chapters, I'll show you several concrete examples of how to set up **HTTPS** for **FastAPI** applications. 🔒


docs/en/docs/deployment/index.md::Deployment { #deployment }::L1

# Doc: docs/en/docs/deployment/index.md | Page: Deployment { #deployment } | Section: Deployment { #deployment }
# Deployment { #deployment }

Deploying a **FastAPI** application is relatively easy.


docs/en/docs/deployment/index.md::What Does Deployment Mean { #what-does-deployment-mean }::L5

# Doc: docs/en/docs/deployment/index.md | Page: Deployment { #deployment } | Section: What Does Deployment Mean { #what-does-deployment-mean }
## What Does Deployment Mean { #what-does-deployment-mean }

To **deploy** an application means to perform the necessary steps to make it **available to the users**.

For a **web API**, it normally involves putting it in a **remote machine**, with a **server program** that provides good performance, stability, etc, so that your **users** can **access** the application efficiently and without interruptions or problems.

This is in contrast to the **development** stages, where you are constantly changing the code, breaking it and fixing it, stopping and restarting the development server, etc.


docs/en/docs/deployment/index.md::Deployment Strategies { #deployment-strategies }::L13

# Doc: docs/en/docs/deployment/index.md | Page: Deployment { #deployment } | Section: Deployment Strategies { #deployment-strategies }
## Deployment Strategies { #deployment-strategies }

There are several ways to do it depending on your specific use case and the tools that you use.

You could **deploy a server** yourself using a combination of tools, you could use a **cloud service** that does part of the work for you, or other possible options.

For example, we, the team behind FastAPI, built [**FastAPI Cloud**](https://fastapicloud.com), to make deploying FastAPI apps to the cloud as streamlined as possible, with the same developer experience of working with FastAPI.

I will show you some of the main concepts you should probably keep in mind when deploying a **FastAPI** application (although most of it applies to any other type of web application).

You will see more details to keep in mind and some of the techniques to do it in the next sections. ✨


docs/en/docs/deployment/manually.md::Run a Server Manually { #run-a-server-manually }::L1

# Doc: docs/en/docs/deployment/manually.md | Page: Run a Server Manually { #run-a-server-manually } | Section: Run a Server Manually { #run-a-server-manually }
# Run a Server Manually { #run-a-server-manually }


docs/en/docs/deployment/manually.md::Use the `fastapi run` Command { #use-the-fastapi-run-command }::L3

# Doc: docs/en/docs/deployment/manually.md | Page: Run a Server Manually { #run-a-server-manually } | Section: Use the `fastapi run` Command { #use-the-fastapi-run-command }
## Use the `fastapi run` Command { #use-the-fastapi-run-command }

In short, use `fastapi run` to serve your FastAPI application:

<div class="termy">

```console
$ <font color="#4E9A06">fastapi</font> run <u style="text-decoration-style:solid">main.py</u>

  <span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span>  Starting production server 🚀

             Searching for package file structure from directories
             with <font color="#3465A4">__init__.py</font> files
             Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>

   <span style="background-color:#007166"><font color="#D3D7CF"> module </font></span>  🐍 main.py

     <span style="background-color:#007166"><font color="#D3D7CF"> code </font></span>  Importing the FastAPI app object from the module with
             the following code:

             <u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>

      <span style="background-color:#007166"><font color="#D3D7CF"> app </font></span>  Using import string: <font color="#3465A4">main:app</font>

   <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span>  Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
   <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span>  Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>

             Logs:

     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Started server process <b>[</b><font color="#34E2E2"><b>2306215</b></font><b>]</b>
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Waiting for application startup.
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Application startup complete.
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C
             to quit<b>)</b>
```

</div>

That would work for most of the cases. 😎

You could use that command for example to start your **FastAPI** app in a container, in a server, etc.


docs/en/docs/deployment/manually.md::ASGI Servers { #asgi-servers }::L45

# Doc: docs/en/docs/deployment/manually.md | Page: Run a Server Manually { #run-a-server-manually } | Section: ASGI Servers { #asgi-servers }
## ASGI Servers { #asgi-servers }

Let's go a little deeper into the details.

FastAPI uses a standard for building Python web frameworks and servers called <abbr title="Asynchronous Server Gateway Interface">ASGI</abbr>. FastAPI is an ASGI web framework.

The main thing you need to run a **FastAPI** application (or any other ASGI application) in a remote server machine is an ASGI server program like **Uvicorn**, this is the one that comes by default in the `fastapi` command.

There are several alternatives, including:

* [Uvicorn](https://www.uvicorn.dev/): a high performance ASGI server.
* [Hypercorn](https://hypercorn.readthedocs.io/): an ASGI server compatible with HTTP/2 and Trio among other features.
* [Daphne](https://github.com/django/daphne): the ASGI server built for Django Channels.
* [Granian](https://github.com/emmett-framework/granian): A Rust HTTP server for Python applications.


docs/en/docs/deployment/manually.md::Server Machine and Server Program { #server-machine-and-server-program }::L60

# Doc: docs/en/docs/deployment/manually.md | Page: Run a Server Manually { #run-a-server-manually } | Section: Server Machine and Server Program { #server-machine-and-server-program }
## Server Machine and Server Program { #server-machine-and-server-program }

There's a small detail about names to keep in mind. 💡

The word "**server**" is commonly used to refer to both the remote/cloud computer (the physical or virtual machine) and also the program that is running on that machine (e.g. Uvicorn).

Just keep in mind that when you read "server" in general, it could refer to one of those two things.

When referring to the remote machine, it's common to call it **server**, but also **machine**, **VM** (virtual machine), **node**. Those all refer to some type of remote machine, normally running Linux, where you run programs.


docs/en/docs/deployment/manually.md::Install the Server Program { #install-the-server-program }::L70

# Doc: docs/en/docs/deployment/manually.md | Page: Run a Server Manually { #run-a-server-manually } | Section: Install the Server Program { #install-the-server-program }
## Install the Server Program { #install-the-server-program }

When you install FastAPI, it comes with a production server, Uvicorn, and you can start it with the `fastapi run` command.

But you can also install an ASGI server manually.

Make sure you create a [virtual environment](../virtual-environments.md), activate it, and then you can install the server application.

For example, to install Uvicorn:

<div class="termy">

```console
$ pip install "uvicorn[standard]"

---> 100%
```

</div>

A similar process would apply to any other ASGI server program.

/// tip

By adding the `standard`, Uvicorn will install and use some recommended extra dependencies.

That includes `uvloop`, the high-performance drop-in replacement for `asyncio`, that provides the big concurrency performance boost.

When you install FastAPI with something like `pip install "fastapi[standard]"` you already get `uvicorn[standard]` as well.

///


docs/en/docs/deployment/manually.md::Run the Server Program { #run-the-server-program }::L102

# Doc: docs/en/docs/deployment/manually.md | Page: Run a Server Manually { #run-a-server-manually } | Section: Run the Server Program { #run-the-server-program }
## Run the Server Program { #run-the-server-program }

If you installed an ASGI server manually, you would normally need to pass an import string in a special format for it to import your FastAPI application:

<div class="termy">

```console
$ uvicorn main:app --host 0.0.0.0 --port 80

<span style="color: green;">INFO</span>:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
```

</div>

/// note

The command `uvicorn main:app` refers to:

* `main`: the file `main.py` (the Python "module").
* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.

It is equivalent to:

```Python
from main import app
```

///

Each alternative ASGI server program would have a similar command, you can read more in their respective documentation.

/// warning

Uvicorn and other servers support a `--reload` option that is useful during development.

The `--reload` option consumes much more resources, is more unstable, etc.

It helps a lot during **development**, but you **shouldn't** use it in **production**.

///


docs/en/docs/deployment/manually.md::Deployment Concepts { #deployment-concepts }::L143

# Doc: docs/en/docs/deployment/manually.md | Page: Run a Server Manually { #run-a-server-manually } | Section: Deployment Concepts { #deployment-concepts }
## Deployment Concepts { #deployment-concepts }

These examples run the server program (e.g Uvicorn), starting **a single process**, listening on all the IPs (`0.0.0.0`) on a predefined port (e.g. `80`).

This is the basic idea. But you will probably want to take care of some additional things, like:

* Security - HTTPS
* Running on startup
* Restarts
* Replication (the number of processes running)
* Memory
* Previous steps before starting

I'll tell you more about each of these concepts, how to think about them, and some concrete examples with strategies to handle them in the next chapters. 🚀


docs/en/docs/deployment/server-workers.md::Server Workers - Uvicorn with Workers { #server-workers-uvicorn-with-workers }::L1

# Doc: docs/en/docs/deployment/server-workers.md | Page: Server Workers - Uvicorn with Workers { #server-workers-uvicorn-with-workers } | Section: Server Workers - Uvicorn with Workers { #server-workers-uvicorn-with-workers }
# Server Workers - Uvicorn with Workers { #server-workers-uvicorn-with-workers }

Let's check back those deployment concepts from before:

* Security - HTTPS
* Running on startup
* Restarts
* **Replication (the number of processes running)**
* Memory
* Previous steps before starting

Up to this point, with all the tutorials in the docs, you have probably been running a **server program**, for example, using the `fastapi` command, that runs Uvicorn, running a **single process**.

When deploying applications you will probably want to have some **replication of processes** to take advantage of **multiple cores** and to be able to handle more requests.

As you saw in the previous chapter about [Deployment Concepts](concepts.md), there are multiple strategies you can use.

Here I'll show you how to use **Uvicorn** with **worker processes** using the `fastapi` command or the `uvicorn` command directly.

/// note

If you are using containers, for example with Docker or Kubernetes, I'll tell you more about that in the next chapter: [FastAPI in Containers - Docker](docker.md).

In particular, when running on **Kubernetes** you will probably **not** want to use workers and instead run **a single Uvicorn process per container**, but I'll tell you about it later in that chapter.

///


docs/en/docs/deployment/server-workers.md::Multiple Workers { #multiple-workers }::L28

# Doc: docs/en/docs/deployment/server-workers.md | Page: Server Workers - Uvicorn with Workers { #server-workers-uvicorn-with-workers } | Section: Multiple Workers { #multiple-workers }
## Multiple Workers { #multiple-workers }

You can start multiple workers with the `--workers` command line option:

//// tab | `fastapi`

If you use the `fastapi` command:

```console
$ <font color="#4E9A06">fastapi</font> run --workers 4 <u style="text-decoration-style:solid">main.py</u>

  <span style="background-color:#009485"><font color="#D3D7CF"> FastAPI </font></span>  Starting production server 🚀

             Searching for package file structure from directories with
             <font color="#3465A4">__init__.py</font> files
             Importing from <font color="#75507B">/home/user/code/</font><font color="#AD7FA8">awesomeapp</font>

   <span style="background-color:#007166"><font color="#D3D7CF"> module </font></span>  🐍 main.py

     <span style="background-color:#007166"><font color="#D3D7CF"> code </font></span>  Importing the FastAPI app object from the module with the
             following code:

             <u style="text-decoration-style:solid">from </u><u style="text-decoration-style:solid"><b>main</b></u><u style="text-decoration-style:solid"> import </u><u style="text-decoration-style:solid"><b>app</b></u>

      <span style="background-color:#007166"><font color="#D3D7CF"> app </font></span>  Using import string: <font color="#3465A4">main:app</font>

   <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span>  Server started at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font>
   <span style="background-color:#007166"><font color="#D3D7CF"> server </font></span>  Documentation at <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000/docs</u></font>

             Logs:

     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Uvicorn running on <font color="#729FCF"><u style="text-decoration-style:solid">http://0.0.0.0:8000</u></font> <b>(</b>Press CTRL+C to
             quit<b>)</b>
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Started parent process <b>[</b><font color="#34E2E2"><b>27365</b></font><b>]</b>
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Started server process <b>[</b><font color="#34E2E2"><b>27368</b></font><b>]</b>
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Started server process <b>[</b><font color="#34E2E2"><b>27369</b></font><b>]</b>
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Started server process <b>[</b><font color="#34E2E2"><b>27370</b></font><b>]</b>
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Started server process <b>[</b><font color="#34E2E2"><b>27367</b></font><b>]</b>
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Waiting for application startup.
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Waiting for application startup.
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Waiting for application startup.
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Waiting for application startup.
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Application startup complete.
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Application startup complete.
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Application startup complete.
     <span style="background-color:#007166"><font color="#D3D7CF"> INFO </font></span>  Application startup complete.
```

////

//// tab | `uvicorn`

If you prefer to use the `uvicorn` command directly:

```console
$ uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
<font color="#A6E22E">INFO</font>:     Uvicorn running on <b>http://0.0.0.0:8080</b> (Press CTRL+C to quit)
<font color="#A6E22E">INFO</font>:     Started parent process [<font color="#A1EFE4"><b>27365</b></font>]
<font color="#A6E22E">INFO</font>:     Started server process [<font color="#A1EFE4">27368</font>]
<font color="#A6E22E">INFO</font>:     Waiting for application startup.
<font color="#A6E22E">INFO</font>:     Application startup complete.
<font color="#A6E22E">INFO</font>:     Started server process [<font color="#A1EFE4">27369</font>]
<font color="#A6E22E">INFO</font>:     Waiting for application startup.
<font color="#A6E22E">INFO</font>:     Application startup complete.
<font color="#A6E22E">INFO</font>:     Started server process [<font color="#A1EFE4">27370</font>]
<font color="#A6E22E">INFO</font>:     Waiting for application startup.
<font color="#A6E22E">INFO</font>:     Application startup complete.
<font color="#A6E22E">INFO</font>:     Started server process [<font color="#A1EFE4">27367</font>]
<font color="#A6E22E">INFO</font>:     Waiting for application startup.
<font color="#A6E22E">INFO</font>:     Application startup complete.
```

////

The only new option here is `--workers` telling Uvicorn to start 4 worker processes.

You can also see that it shows the **PID** of each process, `27365` for the parent process (this is the **process manager**) and one for each worker process: `27368`, `27369`, `27370`, and `27367`.


docs/en/docs/deployment/server-workers.md::Deployment Concepts { #deployment-concepts }::L114

# Doc: docs/en/docs/deployment/server-workers.md | Page: Server Workers - Uvicorn with Workers { #server-workers-uvicorn-with-workers } | Section: Deployment Concepts { #deployment-concepts }
## Deployment Concepts { #deployment-concepts }

Here you saw how to use multiple **workers** to **parallelize** the execution of the application, take advantage of **multiple cores** in the CPU, and be able to serve **more requests**.

From the list of deployment concepts from above, using workers would mainly help with the **replication** part, and a little bit with the **restarts**, but you still need to take care of the others:

* **Security - HTTPS**
* **Running on startup**
* ***Restarts***
* Replication (the number of processes running)
* **Memory**
* **Previous steps before starting**


docs/en/docs/deployment/server-workers.md::Containers and Docker { #containers-and-docker }::L127

# Doc: docs/en/docs/deployment/server-workers.md | Page: Server Workers - Uvicorn with Workers { #server-workers-uvicorn-with-workers } | Section: Containers and Docker { #containers-and-docker }
## Containers and Docker { #containers-and-docker }

In the next chapter about [FastAPI in Containers - Docker](docker.md) I'll explain some strategies you could use to handle the other **deployment concepts**.

I'll show you how to **build your own image from scratch** to run a single Uvicorn process. It is a simple process and is probably what you would want to do when using a distributed container management system like **Kubernetes**.


docs/en/docs/deployment/server-workers.md::Recap { #recap }::L133

# Doc: docs/en/docs/deployment/server-workers.md | Page: Server Workers - Uvicorn with Workers { #server-workers-uvicorn-with-workers } | Section: Recap { #recap }
## Recap { #recap }

You can use multiple worker processes with the `--workers` CLI option with the `fastapi` or `uvicorn` commands to take advantage of **multi-core CPUs**, to run **multiple processes in parallel**.

You could use these tools and ideas if you are setting up **your own deployment system** while taking care of the other deployment concepts yourself.

Check out the next chapter to learn about **FastAPI** with containers (e.g. Docker and Kubernetes). You will see that those tools have simple ways to solve the other **deployment concepts** as well. ✨


docs/en/docs/deployment/versions.md::About FastAPI versions { #about-fastapi-versions }::L1

# Doc: docs/en/docs/deployment/versions.md | Page: About FastAPI versions { #about-fastapi-versions } | Section: About FastAPI versions { #about-fastapi-versions }
# About FastAPI versions { #about-fastapi-versions }

**FastAPI** is already being used in production in many applications and systems. And the test coverage is kept at 100%. But its development is still moving quickly.

New features are added frequently, bugs are fixed regularly, and the code is still continuously improving.

That's why the current versions are still `0.x.x`, this reflects that each version could potentially have breaking changes. This follows the [Semantic Versioning](https://semver.org/) conventions.

You can create production applications with **FastAPI** right now (and you have probably been doing it for some time), you just have to make sure that you use a version that works correctly with the rest of your code.


docs/en/docs/deployment/versions.md::Pin your `fastapi` version { #pin-your-fastapi-version }::L11

# Doc: docs/en/docs/deployment/versions.md | Page: About FastAPI versions { #about-fastapi-versions } | Section: Pin your `fastapi` version { #pin-your-fastapi-version }
## Pin your `fastapi` version { #pin-your-fastapi-version }

The first thing you should do is to "pin" the version of **FastAPI** you are using to the specific latest version that you know works correctly for your application.

For example, let's say you are using version `0.112.0` in your app.

If you use a `requirements.txt` file you could specify the version with:

```txt
fastapi[standard]==0.112.0
```

that would mean that you would use exactly the version `0.112.0`.

Or you could also pin it with:

```txt
fastapi[standard]>=0.112.0,<0.113.0
```

that would mean that you would use the versions `0.112.0` or above, but less than `0.113.0`, for example, a version `0.112.2` would still be accepted.

If you use any other tool to manage your installations, like `uv`, Poetry, Pipenv, or others, they all have a way that you can use to define specific versions for your packages.


docs/en/docs/deployment/versions.md::Available versions { #available-versions }::L35

# Doc: docs/en/docs/deployment/versions.md | Page: About FastAPI versions { #about-fastapi-versions } | Section: Available versions { #available-versions }
## Available versions { #available-versions }

You can see the available versions (e.g. to check what is the current latest) in the [Release Notes](../release-notes.md).


docs/en/docs/deployment/versions.md::About versions { #about-versions }::L39

# Doc: docs/en/docs/deployment/versions.md | Page: About FastAPI versions { #about-fastapi-versions } | Section: About versions { #about-versions }
## About versions { #about-versions }

Following the Semantic Versioning conventions, any version below `1.0.0` could potentially add breaking changes.

FastAPI also follows the convention that any "PATCH" version change is for bug fixes and non-breaking changes.

/// tip

The "PATCH" is the last number, for example, in `0.2.3`, the PATCH version is `3`.

///

So, you should be able to pin to a version like:

```txt
fastapi>=0.45.0,<0.46.0
```

Breaking changes and new features are added in "MINOR" versions.

/// tip

The "MINOR" is the number in the middle, for example, in `0.2.3`, the MINOR version is `2`.

///


docs/en/docs/deployment/versions.md::Upgrading the FastAPI versions { #upgrading-the-fastapi-versions }::L65

# Doc: docs/en/docs/deployment/versions.md | Page: About FastAPI versions { #about-fastapi-versions } | Section: Upgrading the FastAPI versions { #upgrading-the-fastapi-versions }
## Upgrading the FastAPI versions { #upgrading-the-fastapi-versions }

You should add tests for your app.

With **FastAPI** it's very easy (thanks to Starlette), check the docs: [Testing](../tutorial/testing.md)

After you have tests, then you can upgrade the **FastAPI** version to a more recent one, and make sure that all your code is working correctly by running your tests.

If everything is working, or after you make the necessary changes, and all your tests are passing, then you can pin your `fastapi` to that new recent version.


docs/en/docs/deployment/versions.md::About Starlette { #about-starlette }::L75

# Doc: docs/en/docs/deployment/versions.md | Page: About FastAPI versions { #about-fastapi-versions } | Section: About Starlette { #about-starlette }
## About Starlette { #about-starlette }

You shouldn't pin the version of `starlette`.

Different versions of **FastAPI** will use a specific newer version of Starlette.

So, you can just let **FastAPI** use the correct Starlette version.


docs/en/docs/deployment/versions.md::About Pydantic { #about-pydantic }::L83

# Doc: docs/en/docs/deployment/versions.md | Page: About FastAPI versions { #about-fastapi-versions } | Section: About Pydantic { #about-pydantic }
## About Pydantic { #about-pydantic }

Pydantic includes the tests for **FastAPI** with its own tests, so new versions of Pydantic (above `1.0.0`) are always compatible with FastAPI.

You can pin Pydantic to any version above `1.0.0` that works for you.

For example:

```txt
pydantic>=2.7.0,<3.0.0
```


docs/en/docs/editor-support.md::Editor Support { #editor-support }::L1

# Doc: docs/en/docs/editor-support.md | Page: Editor Support { #editor-support } | Section: Editor Support { #editor-support }
# Editor Support { #editor-support }

The official [FastAPI Extension](https://marketplace.visualstudio.com/items?itemName=FastAPILabs.fastapi-vscode) enhances your FastAPI development workflow with *path operation* discovery, navigation, as well as FastAPI Cloud deployment, and live log streaming.

For more details about the extension, refer to the README on the [GitHub repository](https://github.com/fastapi/fastapi-vscode).