Deploying a Flask or FastAPI project to Railway
Content Index
- What is Railway and why use it for your Flask or FastAPI apps
- Local project preparation
- Prerequisites and virtual environment
- Configuring the requirements.txt file
- Production server with Uvicorn for Flask
- Production server with Uvicorn for FastAPI
- Database configuration
- Why use SQLite on the free plan
- Alternatives with PostgreSQL or MySQL
- Migrations and schema synchronization
- Connecting the project with Railway
- Railway CLI installation and authentication
- Link project and execute commands
- If you are NOT going to use SQLite, if you ARE going to use SQLite
- If you already uploaded the db.sqlite3 file before
- Conclusion
- Frequently Asked Questions (FAQs)
Deploying a Flask or FastAPI application doesn't have to be complicated. In this guide, I explain how to do it using **Railway**, a modern platform that simplifies the cloud deployment process. If you've worked with Django, you'll notice that the flow is very similar, just with some specific adjustments for Flask and FastAPI.
Railway lets you connect your GitHub repository, create databases, and deploy your app in minutes. I've used this service several times, even with the free plan, and I can tell you it's one of the simplest options for small projects or production tests.
What is Railway and why use it for your Flask or FastAPI apps
Railway is a continuous deployment platform that allows you to host web applications, APIs, and databases without worrying about the infrastructure. Everything is managed from a very intuitive dashboard or from its CLI.
In this article, we talk more about what Railway is.
Local project preparation
Before deploying, make sure your environment is configured correctly.
Prerequisites and virtual environment
Create a virtual environment and verify that your Flask or FastAPI application works locally. This will prevent errors during deployment.
Configuring the requirements.txt file
Make sure to include all project dependencies. In my case, I added Uvicorn, the web server I use in production. Railway automatically installs what it finds in this file.
Example of requirements.txt:
flask fastapi uvicorn gunicorn sqlalchemyProduction server with Uvicorn for Flask
For production, define the command that will run the application. Railway automatically assigns the port, so don't declare it manually:
uvicorn app:app --host=0.0.0.0 --port=${PORT}Up until now, we have been using a development server, which is perfectly clear when running a Flask application:
$ python run.py *** WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:5000 ***We must install one for production; for Python web, gunicorn is usually an excellent choice:
$ pip install gunicornRailway needs a Procfile to know how to execute your app; this file tells deployment platforms like Tailway or Heroku, to name a few, how to deploy the application, that is, how to start the app, in this case, the command of the installed web server:
web: gunicorn -b 0.0.0.0:$PORT run:appWith the previous command, we execute the application called run.py (run:app) with gunicorn on the dynamically exposed port in the environment variable created by Railway **$PORT** on any IP assigned by Railway (0.0.0.0) -it listens on all available network interfaces inside the container and not just on localhost-. the -b is only to make a binding to the previous IP and port.
Production server with Uvicorn for FastAPI
Unlike Flask, which is a WSGI framework and not ASGI, which is why in the case of Flask it is enough to install only Gunicorn, FastAPI is an ASGI framework and not WSGI, so we also need to install Uvicorn:
$ pip install uvicornGunicorn and Uvicorn are used together because each one fulfills a distinct and complementary role: Uvicorn is the ASGI server that directly runs the FastAPI application, while Gunicorn acts as a process manager that launches and supervises multiple instances (workers) of Uvicorn to take advantage of multiple server cores. In production, this combination allows handling more simultaneous traffic, restarting failed workers, and keeping the application stable and efficient.
Railway needs a Procfile to know how to execute your app; this file tells deployment platforms like Tailway or Heroku, to name a few, how to deploy the application, that is, how to start the app, in this case, the command of the installed web server:
web: gunicorn -k uvicorn.workers.UvicornWorker -b 0.0.0.0:$PORT api:appWith the previous command, we execute the application called run.py (api:app) with gunicorn on the dynamically exposed port in the environment variable created by Railway **$PORT** on any IP assigned by Railway (0.0.0.0) -it listens on all available network interfaces inside the container and not just on localhost-. the -b is only to make a binding to the previous IP and port.
-k uvicorn.workers.UvicornWorker
- Tells Gunicorn to use Uvicorn as a worker.
- Necessary because FastAPI is ASGI and Gunicorn alone does not understand ASGI.
- Uvicorn runs your FastAPI app and Gunicorn manages it as multiple processes.
The Procfile must be located inside the project folder (at the same level as **run.py**).
Database configuration
In this section, we will configure the database; you have to do this whether the project is in Flask or FastAPI. The only change in the deployment is when configuring gunicorn, which was shown previously.
Why use SQLite on the free plan
On the free plan, services "sleep" when not in use. This can generate 500 errors if the database is also suspended. That's why I recommend using **SQLite**: it avoids those errors and doesn't rely on external services.
Alternatives with PostgreSQL or MySQL
If your application needs more robust databases, Railway offers free instances of PostgreSQL and MySQL. Just make sure to include the migrations and upload them to GitHub so that Railway executes them correctly.
Migrations and schema synchronization
Railway does not allow directly uploading SQL files to execute migrations, so you will have to do it via commands. If you use SQLAlchemy or Alembic, it will be enough to run the commands from the Railway CLI.
Connecting the project with Railway
In this article, we explain how to deploy a Django project on Railway; specifically, from there you have to consult the section on creating the database (if you want) and creating the container for the app; they are exactly the same steps, from creating the container to integrating GitHub...
Railway CLI installation and authentication
Railway CLI is the command-line tool for Railway, which allows you to manage projects and services directly from the terminal, without depending on the web dashboard.
Install the Railway CLI with Node.js or Brew (on macOS):
$ npm i -g @railway/cliLog in with:
$ railway loginLink project and execute commands
To work directly from your machine within the remote environment, link your project:
$ railway linkThis will allow you to execute commands in the production container.
Apply migrations in production; to do this, first, configure your production settings **LOCALLY**:
mysql+pymysql://root:twgYYhRdwy***lUUe@mysql.railway.internal:3306/railway
With the project linked, execute the usual commands of your framework. For example, if you use Flask-Migrate or Alembic:
python -m app db init
python -m app db migrate
python -m app db upgradeIf you are NOT going to use SQLite, if you ARE going to use SQLite
You can use the SQLite database but with important limitations, such as it will be overwritten every time you make a new deploy from Railway; this is not a problem if you simply want to use the application as a demo or to present to a client. With this, you can skip creating the database container and using the Railway CLI to execute migrations; to do this, what you must do is remove
.gitignore
# Ignore SQLite database *.sqlite3 *.dbAnd synchronize on GitHub:
$ git add db.sqlite3 $ git commit -m "Add SQLite database" $ git push origin mainIt is important to clarify that it is usually NOT recommended to synchronize the SQLite database on GitHub to avoid conflicts, therefore, you can later revert these changes once synchronized.
Once this is done, you apply the following changes in the project:
SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(basedir, "dev.db")If you already uploaded the db.sqlite3 file before
Git will continue to track it, even if you put it in .gitignore,
because it's already in the history.
To stop tracking it, do this:
git rm --cached db.sqlite3And then commit:
$ git commit -m "Stop tracking db.sqlite3 and add it to .gitignore" $ git pushConclusion
The process of deploying Flask and FastAPI on Railway is almost identical to that of Django: you just need to prepare the requirements.txt file, configure the environment variables, connect the GitHub repository, and launch the app with Uvicorn. The advantage is that Railway simplifies the steps and offers a free plan with very good integration.
Personally, I have found it to be an agile tool, especially for prototypes and personal projects. With a little organization and migrations ready, you can have your API or web app online in a matter of minutes.
Frequently Asked Questions (FAQs)
Can I deploy Flask and FastAPI in the same environment?
Yes, as long as each service runs in a distinct container or with separate routes.
Is Railway better than Render or Heroku for small apps?
For personal or educational projects, Railway is usually faster to set up and offers a more stable free plan.
How to scale an app on the free plan?
You can upgrade the plan or divide the application into microservices, although the free plan is designed for light usage.
I agree to receive announcements of interest about this Blog.
We show the steps to deploy a project in Flask and FastAPI to Railway.