- Quickstarts
- Django
Deploy a Django App on Render
This guide walks through deploying a Django Python app on Render. You can use your existing Django project or create one from scratch.
If you’re new to Django, we recommend first reading the official guide to Writing your first Django project.
To prepare an existing Django project for production on Render, we’ll make a couple adjustments to its configuration:
- We’ll update your project to use a Render PostgreSQL database instead of a SQLite database.
- We’ll configure the WhiteNoise package to serve your project’s static files.
- We’ll define a build script to run with each deploy.
As part of deploying your project, we’ll also deploy a Render PostgreSQL database to serve as its backing datastore. To enable this, let’s add a couple of packages to your project:
Package | Description |
---|---|
psycopg2 | This is the most popular Python adapter for communicating with a PostgreSQL database. |
DJ-Database-URL | This enables you to specify your database details via the DATABASE_URL environment variable (you’ll obtain your database’s URL from the Render Dashboard). |
-
Run the following commands to install these packages:
$ pip install psycopg2-binary $ pip install dj-database-url # Add these dependencies to your requirements.txt file: $ pip freeze > requirements.txt
-
Open
settings.py
in your project’s main directory (e.g.,mysite/settings.py
).Make the following modifications:
# Import dj-database-url at the beginning of the file. import dj_database_url
# Replace the SQLite DATABASES configuration with PostgreSQL: DATABASES = { 'default': dj_database_url.config( # Replace this value with your local database's connection string. default='postgresql://postgres:postgres@localhost:5432/mysite', conn_max_age=600 )}
Django provides a dedicated module for collecting your project’s static files (HTML, CSS, JavaScript, images, and so on) into a single place for serving in production. This module supports moving files from one place to another, relying on the end web server (such as Render’s default web server, or a tool like NGINX) to serve them to end users.
In this step, we’ll set up WhiteNoise to serve these static assets from Render’s web server.
The following instructions summarize the setup described in the WhiteNoise documentation.
-
Add WhiteNoise as a dependency (adding Brotli support is optional, but recommended):
$ pip install 'whitenoise[brotli]' $ pip freeze > requirements.txt
-
Open
settings.py
in your project’s main directory (e.g.,mysite/settings.py
).Add the following to the
MIDDLEWARE
list, immediately afterSecurityMiddleware
:MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', ... ]
-
Still in
settings.py
, find the section where static files are configured.Make the following modifications:
# Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.0/howto/static-files/ # This setting informs Django of the URI path from which your static files will be served to users # Here, they well be accessible at your-domain.onrender.com/static/... or yourcustomdomain.com/static/... STATIC_URL = '/static/' # This production code might break development mode, so we check whether we're in DEBUG mode if not DEBUG: # Tell Django to copy static assets into a path called `staticfiles` (this is specific to Render) STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # Enable the WhiteNoise storage backend, which compresses static files to reduce disk use # and renames the files with unique names for each version to support long-term caching STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
All set! We’re ready to serve static content from our Django project on Render.
Whenever you deploy a new version of your project, Render runs a build command to prepare it for production. Let’s create a script for Render to run as this build command.
-
Create a new file called
build.sh
in your project’s root directory and paste in the following:#!/usr/bin/env bash # Exit on error set -o errexit # Modify this line as needed for your package manager (pip, poetry, etc.) pip install -r requirements.txt # Convert static asset files python manage.py collectstatic --no-input # Apply any outstanding database migrations python manage.py migrate
Make sure the script is executable before adding it to version control:
chmod a+x build.sh
We’ll configure Render to run this build script whenever a new deploy is initiated.
-
We’ll run your project with Uvicorn and Gunicorn. Add these dependencies to your project:
pip install gunicorn uvicorn pip freeze > requirements.txt
-
Try running your project locally!
Replace
mysite
in the command below with your project’s name.python -m gunicorn mysite.asgi:application -k uvicorn.workers.UvicornWorker
-
Visit http://localhost:8000 in your browser to verify that your project is up and running.
Commit all changes and push them to your repository. Your project is ready to deploy to Render!
There are two ways to deploy your Django project on Render, either by declaring your services within your repository using a render.yaml
file or by manually setting up your services using the dashboard. In this tutorial, we will walk through both options.
render.yaml
for deploys
-
Create a file named
render.yaml
in the root of your project. This file will define your Django web service, along with the database it connects to. Don’t forget to commit and push it to your repository.The
gunicorn
command in the highlighted line below assumes your Django project is namedmysite
. Update it for your project as needed.databases: - name: mysitedb plan: free databaseName: mysite user: mysite services: - type: web plan: free name: mysite runtime: python buildCommand: "./build.sh" startCommand: "python -m gunicorn mysite.asgi:application -k uvicorn.workers.UvicornWorker" envVars: - key: DATABASE_URL fromDatabase: name: mysitedb property: connectionString - key: SECRET_KEY generateValue: true - key: WEB_CONCURRENCY value: 4
-
In the Render Dashboard, go to the Blueprints page and click New Blueprint Instance.
-
Select the repository that contains your blueprint and click Connect.
-
Give your blueprint project a name and click Apply.
That’s it! Your project will be live at its .onrender.com
URL as soon as the build finishes.
-
Create a new PostgreSQL database on Render. Copy its internal database URL for now—you’ll need it later.
-
Create a new web service on Render, pointing it to your project’s GitHub/GitLab/Bitbucket repository (give Render permission to access it if you haven’t already).
-
Select
Python
for the runtime and set the following properties (replacemysite
with your project’s name):Property Value Build Command ./build.sh
Start Command python -m gunicorn mysite.asgi:application -k uvicorn.workers.UvicornWorker
-
Add the following environment variables under Advanced:
Key Value DATABASE_URL
The internal database URL for the database you created above SECRET_KEY
Click Generate to get a secure random value WEB_CONCURRENCY
4
That’s it! Save your web service to deploy your Django application on Render. It will be live on your .onrender.com
URL as soon as the build finishes.
Once your application is live, create a new Django admin account by running the following command in the Render Shell:
python manage.py createsuperuser
See Setting your Python Version if you need to customize the version of Python used for your app.
This section walks through setting up a Django project and adding an application with a simple view.
The finished code for this example is available on GitHub, and you can view the project running here.
This tutorial starts with a bare-bones installation and explains all required code modifications. Feel free to adapt it with custom configuration as needed.
First, we’ll set up our local development environment and create a basic project structure.
We’ll call our project mysite
. You can use a different name, but make sure to modify all commands that use mysite
below to match the name you choose.
Run the following commands in your terminal (see comments for descriptions):
# Create a new project directory and cd into it
mkdir mysite
cd mysite
# Create a virtual environment using Python's venv package
python -m venv venv
# Activate the virtual environment to start installing other packages
source venv/bin/activate
Run the following from your project’s root directory to install Django:
# This installs Django 5.0.1 (feel free to modify the version as needed)
pip install django==5.0.1
pip freeze > requirements.txt
Then run the following to initialize your mysite
Django project:
django-admin startproject mysite .
You’ll end up with the following directory structure:
.
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── venv (you can ignore everything in here for now)
├──
You now have a fully functional scaffold for your new Django project! To verify, you can start the development server:
python manage.py runserver
Then visit http://localhost:8000 in your browser:
Next, we’ll add an application to our Django project that serves a simple landing page.
Django projects contain one or more applications, which are wired together to form a complete service. Django provides several built-in applications, such as its admin site.
-
Run the following command from your project’s root directory:
python manage.py startapp homepage
This creates a directory for a new application named
homepage
with following contents:homepage ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py └── views.py
-
We need to inform Django about this new
homepage
application. Openmysite/settings.py
and find the theINSTALLED_APPS
setting. Add a reference to theHomepageConfig
class to the beginning of the list:INSTALLED_APPS = [ 'homepage.apps.HomepageConfig', 'django.contrib.admin', 'django.contrib.auth', ... ]
For more information about the
INSTALLED_APPS
setting, see the Django settings information page
Let’s create a simple view in our homepage
application that we’ll serve from our service’s root path. First we’ll define the view, then we’ll configure its routing.
-
Create a new file at
homepage/templates/homepage/index.html
. Paste in the following HTML:<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Hello Django on Render!</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> </head> <body> <main class="container"> <div class="row text-center justify-content-center"> <div class="col"> <h1 class="display-4">Hello World!</h1> </div> </div> </main> </body> </html>
Nothing fancy
-
In the file
homepage/views.py
, add the following Python code for theindex
method:from django.shortcuts import render # Create your views here. def index(request): return render(request, 'homepage/index.html', {})
This method renders the
homepage/index.html
template we just created. -
Create a new file named
homepage/urls.py
and paste in the following:from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
This file tells Django that you want to serve the
index
view from your service’s root URL. -
Configure the Django project to point to the
homepage
application’surls
module. Openmysite/urls.py
and update thefrom django.urls import path
line to add theinclude
module, and then include thehomepage
application’s URLs module to oururlpatterns
, like so:from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('', include('homepage.urls')),]
Your folder structure should now look like this:
render ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── templates │ └── render │ └── index.html ├── tests.py ├── urls.py └── views.py
-
Add a static file to your application. Download this image and save it as
homepage/static/homepage/render-banner.png
: -
Return to your
index.html
template. Load thestatic
module and reference the downloaded image in a new<header></header>
block:{% load static %} <!doctype html> <html lang="en"> ... <body> <header class="container mt-4 mb-4"> <a href="https://render.com"> <img src="{% static "homepage/render-banner.png" %}" alt="Homepage banner" class="mw-100"> </a></header>... </body> </html>
-
You can now verify your app is working with the following command:
python manage.py runserver
Reload your browser tab at
localhost:8000
to make sure the banner and text are showing properly.
You should ensure that any production-level application is properly secured and configured. The Django documentation provides a useful deployment checklist, which we’ll follow in this step.
-
Open
mysite/settings.py
and find the declaration of theSECRET_KEY
setting. We don’t want to store production secrets in source code, so we’ll fetch this value from an environment variable that we’ll create later:# Don't forget to import os at the beginning of the file import os
# SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = os.environ.get('SECRET_KEY', default='your secret key')
-
Find the declaration of the
DEBUG
setting. This setting should never be set toTrue
in a production environment. You can detect that you’re running on Render by checking for the presence of theRENDER
environment variable in the application environment:# SECURITY WARNING: don't run with debug turned on in production! DEBUG = 'RENDER' not in os.environ
-
When
DEBUG
isFalse
, Django requires a suitable value forALLOWED_HOSTS
. You can get the name of your web service host from theRENDER_EXTERNAL_HOSTNAME
environment variable, which is automatically set by Render.# https://docs.djangoproject.com/en/3.0/ref/settings/#allowed-hosts ALLOWED_HOSTS = [] RENDER_EXTERNAL_HOSTNAME = os.environ.get('RENDER_EXTERNAL_HOSTNAME')if RENDER_EXTERNAL_HOSTNAME: ALLOWED_HOSTS.append(RENDER_EXTERNAL_HOSTNAME)
If you add a custom domain to your service, don’t forget to add it to this list.
We will add the DJ-Database-URL package, which allows us to specify databases in Django using connection strings. Render provides database connection strings in the Render Dashboard, which you will provide to your web service via the DATABASE_URL
environment variable. We will also need to add psycopg2 to the project.
-
Run the following command to add the necessary dependencies to your project:
$ pip install dj-database-url psycopg2-binary $ pip freeze > requirements.txt
-
In
mysite/settings.py
, find the declaration of theDATABASES
setting and modify it to look like the following:# Import the dj-database-url package at the beginning of the file import dj_database_url
# Database documentation https://docs.djangoproject.com/en/5.0/ref/settings/#databases DATABASES = { 'default': dj_database_url.config( # Replace this value with your local database's connection string. default='postgresql://postgres:postgres@localhost:5432/mysite', conn_max_age=600 )}
This connection string assumes that you have PostgreSQL running on localhost, on port 5432, with a database named
mysite
and a user namedpostgres
with the passwordpostgres
. -
Apply our database migrations. A “migration” is a step-by-step process of creating database tables and fields for our Django project. We will use the
migrate
command to run the migrations:python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying auth.0012_alter_user_first_name_max_length... OK Applying sessions.0001_initial... OK
As a final step, jump back to the top of the document and read the section about Updating an existing Django project to make sure your project is production-ready. Then, follow the instructions in Deploying to Render to deploy your project.