Deploying a FastAPI App to SAP BTP

fastapi
sap
btp
Author

Christian Wittmann

Published

July 10, 2025

In a previous blog post, we created a simple greeting API using FastAPI, entirely within a Jupyter Notebook. This follow-up post shows how to deploy it on SAP Business Technology Platform (SAP BTP), making it accessible from your SAP or non-SAP projects.

(I assume you already have access to an SAP BTP account with Cloud Foundry enabled.)

You’ll learn how to:

In short, we’ll take the FastAPI greeting service from “it works on my machine” to “deployed on SAP BTP.” 🤓

Creating a Local Deployment

Once you’re done developing your FastAPI app in a Jupyter Notebook, you can prepare it for local deployment by following these steps:

Creating app.py

To create the app.py file, follow these steps

  • Copy all the code from the final cell in the Jupyter Notebook and paste it into a new Python file named app.py.
  • Remove notebook-specific dependencies. Anything related to nest_asyncio is no longer needed, it is only necessary in Jupyter notebooks. Additionally, remove the uvicorn.run(...) call, as the server will be launched outside app.py.

Creating requirements.txt

For our simple project, you could easily create the requirements.txt file manually, but I am too lazy for that, so I am using the pipreqs package to generate it for me.

If you don’t have the pipreqs package installed, you can simply install it using pip:

pip install pipreqs

Now you can generate the requirements.txt. Either cd into the directory where your app.py file is located and run

pipreqs .

Alternatively, you can specify the path to the app.py file

pipreqs path/to/app.py

Installing Dependencies

Once you have the requirements.txt file, you can install the dependencies using pip

pip install -r requirements.txt

When you are developing your own app, and you started in a Jupyter notebook, the installation of the dependencies is a self-fulfilling prophecy, but once we move to a virtual environment, you need to install the dependencies.

Running the App

Now you can run your app with Uvicorn from the terminal. From the directory where app.py is located, start the API server with:

uvicorn app:app --reload

Let’s break down the command:

  • uvicorn: The Uvicorn server.
  • app:app: This follows the format :: It tells Uvicorn to look for the FastAPI app instance named app inside the Python module app.py. Since both arguments are the same, let’s change it for clarity. If you had written greeting_app = FastAPI() inside a file called api_app.py, you would run uvicorn api_app:greeting_app --reload
  • --reload: Automatically restarts the server whenever you make code changes — useful during development.

Note for later: When deploying to SAP BTP, you’ll also need to add two files to your app folder: manifest.yaml and Procfile. These are only needed for deployment and not required when testing locally.

Running the App in a Virtual Environment

So far, we have re-created the behavior of the Jupyter Notebook in a Python file. However, when we deploy the app in the cloud, we will have a different environment. To make sure that we defined the dependencies correctly and the app runs as expected, we should test it in a virtual environment. This ensures you’re not relying on any globally installed Python packages from your system or IDE setup.

Creating a Virtual Environment

To create a virtual environment, you can use the venv module that comes with Python. Open your terminal and navigate to the directory where your app.py file is located. Then, run the following command to create a virtual environment named venv:

python -m venv venv

Let’s break down the command:

  • python: The Python interpreter.
  • -m venv: The venv module, which is used to create virtual environments.
  • venv: The name of the virtual environment.

Activating the Virtual Environment

Once the virtual environment is created, you need to activate it. The activation command depends on your operating system:

  • Windows: venv\Scripts\activate
  • macOS/Linux: source venv/bin/activate

As a result, you should see the name of the virtual environment (venv) as a prefix in your terminal.

Installing Dependencies

Now that you have activated the virtual environment, you can install the dependencies using pip. From the directory where app.py is located, run:

pip install -r requirements.txt

Now the virtual environment has all the dependencies from requirements.txt installed, simulating the environment in which the app will be deployed on BTP.

Running the App

Now you can run your app with Uvicorn from the terminal. From the directory where app.py is located, start the API server with:

uvicorn app:app --reload

Deactivating the Virtual Environment

When you are done testing, you can deactivate the virtual environment by running:

deactivate

Preparing for Deployment to SAP BTP

Before deploying our API to SAP BTP using Cloud Foundry, we need to complete a few preparation steps. First, we need to install the Cloud Foundry CLI (unless you want to deploy via the BTP UI which is also possible). Additionally, we need to create two configuration files: manifest.yaml and Procfile. These will define how the application is deployed and run on BTP.

Installing the Cloud Foundry CLI

To interact with Cloud Foundry, the preferred way is to use the cf command-line interface. If you have not installed it yet, you can download and install it from the official Cloud Foundry CLI page.

On macOS, you can conveniently install the current version 8 using brew:

brew install cloudfoundry/tap/cf-cli@8

Once installed, you should be able to run:

cf --version

You should see the version number of the CLI which confirms the CLI is available and ready to use.

Creating the manifest.yaml

The manifest.yaml file defines how Cloud Foundry should deploy your app. It includes metadata such as the app name, memory allocation, number of instances, and route configuration. For a complete reference, please check out the Cloud Foundry Manifest Reference

Create a new file named manifest.yaml in the same folder as your app.py and add the following content:

---
applications:
  - name: greeting-api
    memory: 256M
    instances: 1
    buildpacks:
      - python_buildpack
    path: .
    routes:
      - route: greeting-api-test.cfapps.eu10-004.hana.ondemand.com

Let’s break down the content of the manifest.yaml:

  • name: The name of the app as it will appear in your BTP subaccount.
  • memory: The memory allocated per app instance. 256M is typically sufficient for small FastAPI services.
  • instances: Number of app instances to start (1 for now).
  • buildpacks: Sets the Python buildpack (if not set explicitly, BTP will try to detect it automatically).
  • path: The path to the application directory.
  • routes: The custom URL (host + domain) you want your app to use. You can find the correct domain (e.g. cfapps.eu10-004.hana.ondemand.com) in your BTP subaccount under “Cloud Foundry → Overview → API Endpoint.”

Creating the Procfile

The purpose of a Procfile is to define how your app should be started. While you can specify the start command manually during cf push (this is the command which finally deploy the API on BTP), it’s good practice to include a Procfile for clarity, consistency, and maintainability.

Create a plain text file named Procfile (no extension) in your app’s root directory with the following content:

web: uvicorn app:app --host=0.0.0.0 --port=${PORT:-8080}

Let’s break it down:

  • web: tells the platform that this process handles incoming HTTP requests.
  • uvicorn app:app loads your FastAPI app instance named app from the app.py file.
  • --host=0.0.0.0 makes Uvicorn listen on all network interfaces (required for deployment).
  • --port=${PORT:-8080} uses the port environment variable ($PORT) provided by Cloud Foundry or falls back to port 8080 when running locally.

Deploying the API on SAP BTP

After we’ve successfully tested our API locally and completed all the necessary preparations, it’s time to deploy it to SAP BTP using Cloud Foundry.

To keep things organized, I created a new folder called app-btp and copied the following files into it:

  • app.py – the main FastAPI application
  • requirements.txt – the list of dependencies
  • Procfile – the startup instruction
  • manifest.yaml – the deployment descriptor

To start the deployment, open a terminal, cd into the app-btp directory, and log in to Cloud Foundry using the SAP BTP CLI:

cf login

You’ll be prompted to enter your API endpoint, email, password, org, and space. You can find the API endpoint in your BTP cockpit by navigating to your subaccount and checking the “Cloud Foundry Environment” section.

Once logged in, push your app to BTP:

cf push

Think of cf push like pushing code to GitHub: It copies your application to the BTP environment, sets up the app using the manifest.yaml, installs the dependencies from requirements.txt, and starts the app using the Procfile.

After deployment, your app will be assigned a public URL, as specified in your manifest.yaml. For example:

https://greeting-api-test.cfapps.eu10-004.hana.ondemand.com

You can now test the API using the GET client notebook or the POST client notebook.

Alternative: Deploying via ZIP Upload in the SAP BTP Cockpit

If you prefer to deploy your app via the SAP BTP UI instead of using the CLI, you can also create a ZIP archive and upload it directly through the cockpit.

Simply create a ZIP archive of your app folder containing the following files:

  • app.py
  • requirements.txt
  • Procfile

Make sure there are no folders in the ZIP-file, the files should be in the root of the ZIP archive.

Keep the manifest.yaml as a separate file.

To upload the file for deployment, follow these steps:

  • Navigate to a space in your subaccount
  • Click on “Deploy Application”
  • Upload your app-btp.zip file and the manifest.yaml file
  • Click on “Deploy”

After the deployment is complete, your app will be live under the route you defined in manifest.yaml.

You can now test the API using the GET client notebook or the POST client notebook.

Conclusion

Taking the API from a Jupyter Notebook (my preferred environment for rapid prototyping) to a working cloud deployment took a few steps. First, we refactored the code into a standalone Python file (app.py). Then we created a requirements.txt file and tested everything locally in a clean virtual environment. After creating manifest.yaml and Procfile files, we deployed the API to the cloud using the SAP BTP CLI or the SAP BTP Cockpit.

After building the greeting API in my previous blog post, we’ve now taken it all the way to the cloud. The goal here wasn’t to explore every FastAPI feature or every cloud deployment nuance, but to provide a reusable, step-by-step template for future projects.

There’s lots more you could do, e.g. adding authentication, rate limiting, or monitoring, but we’ll leave that for another time. I Hope this was helpful, and happy coding!