Deploying Django + uv + sqlite to Fly.io
December 6, 2024
I was working on a Django template DHAT Stack and wanted to deploy it, I chose fly.io because of its awesome cli and straight forward deployment process. Though the process to deploy to fly.io is fairly easy, there were some configurations needed to make it production ready. On top of that, I wanted to use uv to manage the python environment and sqlite for the database as the project was a template and didn't require a full fledged Postgres.
I'll divide this blog into two sections, first we will see the configuration needed to make the Django app production ready and then we will see how to deploy it to fly.io.
Making the Django app production ready
Since I'm using uv to manage the python environment, and you're reading this blog, I'm assuming you're using uv as well and have a pyproject.toml
and uv.lock
file in the root of your project.
These files will be used in the fly.io build process to install the dependencies and that's the advantage of using uv that we don't need requirements.txt which is not easy to manage.
Environment variables
I'm using django-environ to manage the environment variables and have a .env
file in the root of the project which is used to set the environment variables.
Create a .env
file in the root of the project and add the following:
Then in the settings.py
file, import the environment variables:
Though here we're reading secret key from the .env
file, we will soon update it to a different method to take the secret key from fly.io secrets and use a generated secret key in development to not get an error during build process as we're going to put .env file in the gitignore and dockerignore.
Gunicorn
Django comes with a built in minimal server which is not recommended for production, we will use gunicorn to serve the app in production. Gunicorn is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model ported from Ruby's Unicorn project.
Let's install gunicorn:
That's it, we will later see how to use gunicorn in the fly.io build process.
Static files
We will use whitenoise to serve the static files. Whitenoise is a Django middleware that serves static files in production.
Let's install whitenoise:
Now we need to update the settings.py
file to use whitenoise:
- Add whitenoise to the middleware after
django.middleware.security.SecurityMiddleware
- Set
STATICFILES_STORAGE
towhitenoise.storage.CompressedManifestStaticFilesStorage
- Set
STATIC_ROOT
to the path where the static files will be collected, I'm usingBASE_DIR / 'staticfiles'
(Optional but recommended) Use whitenoise in development to keep the behavior of the static files the same in development and production, to do this we just need to add whitenoise.runserver_nostatic
to INSTALLED_APPS before django.contrib.staticfiles
.
Other configurations
Update ALLOWED_HOSTS
to a list of domains that our django app will serve, in our case it will be the domain of the fly app.
I'm keeping the name of our fly app as dhat-stack
.
Django also has a setting CSRF_TRUSTED_ORIGINS
which is used to trust the origins of the requests, we need to add the domain of the fly app to this list.
Database
For now, let's add the following to the settings.py
file:
This will make the database use the DATABASE_URL
environment variable if it's available, otherwise it will use sqlite as default.
Deploying to fly.io
Since we're using sqlite, there are some extra steps we need to take for it to work properly in fly.io. To avoid complexity of managing multiple sqlite databases and keeping them in sync accross multiple servers, I'll be deloying my app to only 1 server and using fly.io volumes to persist the database. For small apps this is more than enough.
If you're planning to scale your app to multiple servers, you should use a database that is designed to be scalable like Postgres and a managed databse service like Supabase works great with fly. If you don't want to use a managed database service, fly also has its own semi-managed (or not) postgres database called Fly Postgres.
There might be ways to make sqlite work with multiple servers but I didn't have the need for it, fly also has its own database service called LiteFS, I needed something simple and sqlite worked fine for my use case.
Creating a fly app
Note: You need to have the fly cli installed to be able to do this. Install flyctl
First we need to create a fly app, we can do this by running the following command:
This will create a fly app without deploying it and without high availability (ha) i.e only 1 server.
Creating a volume
To store the sqlite database file even after the app is stopped, we need to create a volume.
I followed the fly.io volumes guide to launch a new fly app with a volume. For an existing fly app, a flyctl command will be needed, you can follow this guide to create a volume for an existing app.
Since I've already created a fly app, the next step is to create a volume.
Now we need to tell fly to mount this volume during the deployment process, we can do this by updating the fly.toml
file.
Now deploy:
Deployment might fail but volumes are created in the background so we can ignore that.
To manually create a volume, you can run the following command:
This will create a volume in the iad
region with a size of 1GB.
Secrets
Now create secrets for the environment variables we added to the .env
file.
We don't need to set a secret key as fly will create it for us.
Dockerfile
If you're using uv, its likely that the Dockerfile generated by flyctl contains poetry config as it detects pyproject.toml and assumes it's a poetry project.
Since uv is new we will have to update the Dockerfile to use uv instead of poetry.
This is the complete Dockerfile I used:
startup.sh
is a simple script that is needed for migrations to work properly. Create it in the root of the project and add the following:
Finally, deploy the app to fly.io:
Conclusion
This guide covered the steps I took to deploy a Django app to fly.io using uv, sqlite and a custom Dockerfile. I hope this guide will help you deploy your Django app to fly.io.
You can find the complete code for the Django app in the DHAT Stack repository.
If you found this guide helpful, please consider giving DHAT Stack repo a star and sharing this blog on bsky or twitter.