> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sevalla.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Django - Deployment

> Find out how to configure and deploy your Django application.

## Application settings

Before you can deploy your app, you need to update your `settings.py` file so your app can run properly in both development and production environments.

If you don't already have a preferred approach to handle your settings, you can use [django-environ](https://django-environ.readthedocs.io/en/latest/). You can install django-environ with your package manager.

```shellsession theme={null}
pip install django-environ
```

django-environ reads values from `.env` in your project's base directory. At a minimum, `.env` needs to include the following variables:

* DEBUG
* SECRET\_KEY
* ALLOWED\_HOSTS
* CSRF\_TRUSTED\_ORIGINS
* DATABASE\_URL

These are the environment variables that typically vary between development and production. You can also add any other project-specific environment variables. This `.env` will only contain your development values.

```shellscript theme={null}
# .env
DEBUG=True # [!code ++:5]
ALLOWED_HOSTS=localhost,127.0.0.1
SECRET_KEY=<your-secret-key-here>
CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://127.0.0.1:8000
DATABASE_URL=sqlite:///db.sqlite3
```

After you've created the `.env` file, you need to update your `settings.py` file so django-environ can read `.env` and set the appropriate settings. `DEBUG` should default to `False`, so your production environment never starts in debug mode.

```python theme={null}
# settings.py
import os # [!code ++]
import environ # [!code ++]

from pathlib import Path

env = environ.Env(DEBUG=(bool, False)) # [!code ++]

BASE_DIR = Path(__file__).resolve().parent.parent

environ.Env.read_env(os.path.join(BASE_DIR, '.env')) # [!code ++]
```

For each setting, you can use the env object to retrieve the value. For values that accept a list, `env.list` will convert comma-separated values to a Python list. If those values don't exist, you should default to an empty list, so you have no allowed hosts or CSRF trusted origins.

```python theme={null}
SECRET_KEY = env('SECRET_KEY') # [!code ++]

DEBUG = env('DEBUG') # [!code ++]

ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[]) # [!code ++]
CSRF_TRUSTED_ORIGINS = env.list('CSRF_TRUSTED_ORIGINS', default=[]) # [!code ++]
```

For the database, use `env.db()` on the default database; this loads the `DATABASE_URL` value defined in your environment variables.

```python theme={null}
# settings.py
DATABASES = {
    'default': { # [!code --:4]
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
    'default': env.db(), # [!code ++]
}
```

## Add a hosted database

The filesystem used for your app will be recreated on each deploy, so an SQLite database isn't suitable for production. Instead, you can use a hosted database on Sevalla for your app.

[Create a database](https://docs.sevalla.com/databases/get-started/add-a-database) in Sevalla and select either Postgres, MySQL, or MariaDB.

You also need to install a database driver if you haven't already done so. For example, with Postgres, you can use `psycopg2-binary`.

```shellsession theme={null}
pip install psycopg2-binary
```

## Application server and static files

Django’s built-in development server is not intended for production use, so you should run your application with Gunicorn instead. Because the development server also handles static files by default, you’ll need to use WhiteNoise to serve static assets in production. Both Gunicorn and WhiteNoise must be installed via your package manager as part of your deployment setup.

```shellsession theme={null}
pip install gunicorn whitenoise
```

To use WhiteNoise, you only need to add its middleware in `settings.py`. This middleware should be placed after the `SecurityMiddleware`.

```python theme={null}
# settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware', # [!code ++]
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
```

For static files to work properly, you need to define the `STATIC_ROOT` variable in `settings.py`.

```python theme={null}
STATIC_ROOT = BASE_DIR / 'staticfiles' # [!code ++]
```

## Nixpacks

By default, Sevalla builds your application using Nixpacks. Nixpacks can detect that you have a Python app, but you need to specify any extra commands needed to build your app. You also need a start command to tell Nixpacks how to start your app. You can define both commands in a `nixpacks.toml` file in your base directory.

For the build command, you need to run `collectstatic`. For the start command, you need to run both the `migrate` and `gunicorn` command. After the `gunicorn` command, specify the name of your Django project followed by `.wsgi`. The `$PORT` variable can be used to start your app on the port defined in your Sevalla application.

```toml theme={null}
[phases.build] # [!code ++:2]
cmds = ["python manage.py collectstatic --noinput"]

[start] # [!code ++:2]
cmd = "python manage.py migrate && gunicorn example.wsgi -b 0.0.0.0:$PORT"
```

Finally, generate a `requirements.txt` file so your dependencies install during deployment.

```shellsession theme={null}
pip freeze > requirements.txt
```

## Dockerfile

To build your application from a Dockerfile, you need a Dockerfile that ends with your application being started by Gunicorn or any other WSGI server.

The following is a sample Dockerfile that sets up a Python environment, installs your dependencies, collects static files, and then starts a Gunicorn server.

```docker theme={null}
FROM python:latest  

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1 
 
RUN mkdir /app
WORKDIR /app
 
RUN pip install --upgrade pip 
COPY requirements.txt  .
RUN pip install --no-cache-dir -r requirements.txt
 
COPY . .

ARG SECRET_KEY
ARG DATABASE_URL

RUN python3 manage.py collectstatic --no-input

CMD ["gunicorn", "example.wsgi"]
```

Django management commands can't run without a secret key and database set, so the `ARG` directive is used to make the associated environment variables available to the build process. These environment variables should be set as available at both buildtime and runtime before deploying your app for the first time.

The command to start with Gunicorn needs to reference the name of your project's WSGI file.

The rest of the Dockerfile can be customized according to your project's specific needs.

### Migrations

Migrations need to happen outside the Dockerfile because there won't be a reference to your actual database in the Dockerfile. Additionally, your migrations must run after your image has been built but before the container is started.

You can [create a job](https://docs.sevalla.com/applications/processes#job-process) to run the migrate command before the container is started. To do this, after you add your application, go to **Processes** > **Create job** > **Job**. For the start command, add `python manage.py migrate`. The start policy should be **before deployment**, and the smallest instance size should be sufficient for migrations.

### Build settings

By default, Sevalla builds applications using Nixpacks, so the [build strategy](https://docs.sevalla.com/applications/settings#build-strategy) must be updated before your Dockerfile can be used.

To update the build strategy, after you add your application, go to **Settings** > **Update build strategy** and change the build strategy from **Nixpacks** to **Dockerfile**.

## Deploy on Sevalla

To deploy your app to [Sevalla using Git](https://docs.sevalla.com/applications/git/overview), your code must be hosted in a Git repository. Sevalla supports any public Git repository or private repositories from GitHub, Bitbucket, and GitLab. You'll need to connect your repo host account with Sevalla if you are using a private repo.

Your repo should have a `.gitignore` that ignores SQLite files, `.env` files, virtual environments, `__pycache__/`, any other files that either have sensitive information or don't need to be tracked in git.

Here is an example .gitignore file:

```text theme={null}
__pycache__/ 
.env
.venv/
env/
venv/
*.sqlite3
```

You can now [add your application](https://docs.sevalla.com/applications/get-started/add-an-application) in Sevalla and choose the branch and repository for your project. Ensure that you set the location for your application to match the location of your database, allowing them to communicate over an internal network.  If your app requires more resources than the defaults of 0.3 GB RAM and 0.3 CPU, then switch to a larger instance size.

After adding the application, you can set up the [environment variables](https://docs.sevalla.com/applications/environment-variables) required for your app. First, go to **Domains** to copy your app’s generated domain. Then go to **Environment variables** to set up the same environment variables defined in `.env` except for `DATABASE_URL`. The values for the variables should be appropriate for production.

* `ALLOWED_HOSTS`: include only the domain with no scheme or trailing slash. (e.g. deploydjangosevalla-4q4g3.sevalla.app).
* `CSRF_TRUSTED_ORGINS`: include the scheme but no trailing slash. (e.g. [https://deploydjangosevalla-4q4g3.sevalla.app](https://deploydjangosevalla-4q4g3.sevalla.app)).
* `DEBUG`: should always be false except for intentional testing.
* `SECRET_KEY`: should be a random string of at least 50 characters.

For the `DATABASE_URL`, go to **Networking** and click **Add internal connection**. Select the database you created earlier, and then select **Add environment variables to the application**. Rename `DB_URL` to `DATABASE_URL` and click **Add internal connection**.
