Deployment Django App on Vercel to server static files

I got a lot of question when I tried to deployment Django App on vercel,

Fortunately, I did it after I took me over 48 hours. so I want to share it to your for saving your time.

You can see that example site that I host Django App On Vercel.

There are still have a few question for me. Let me know if you know why

  1. Why I still have to set STATIC URL in urls.py when BUG is enable. We Know that django can server static files by itself when DEBUG=True.

  2. Why I have run python manage.py collectstatic. This is so weird. We use the path <STATICFILES_DIR> to offer static files when DEBUG=True. Why does I still need to collect static files to <STATIC_ROOT>.

  3. Why do I need to enable DEBUG. Ok. I know that. The django is Framework not a web server. But How should I do server static file when DEBUG Is False.

Step 1: configiure vercel.json for python environment on Vercel

You have to create a file vercel.json in your django project root dir. and then You can build python environment on vercel.

otherwise vercel only build front-end files.

## vercel.json
{
  "version": 2,                                                                                                                                               
  "builds": [
    {   
      "src": "<YOUR PROJECT_NAME>/wsgi.py",
      "use": "@vercel/python",
      "config": { "maxLambdaSize": "15mb", "runtime": "python3.9" }
    },  
    {   
      "src": "build_files.sh",
      "use": "@vercel/static-build",
      "config": {
        "distDir": "vercel/static"                 // YOUR STATIC_ROOT             
      }   
    }   
  ],
  "routes": [
    {   
      "src": "/vercel/path0/vercel/static/(.*)",    // This is a key point. The path = '/vercel/path0' + "STATIC_ROOT"
      "dest": "/static/$1"
    },  
    {   
      "src": "/(.*)",
      "dest": "<YOUR PROJECT_NAME>/wsgi.py"
    }   
  ]
}

Step 2: Build

There a few questions here you need to be aware of

  1. Vercel can't support the sqlite3 db. Although I think it is the best database in the world. You have to install driven for your database. I use a free postgres database that is from Vercel. Let me say that you are generous Vercel. So I need to install psycopg2-binary
  2. Vercel can't server staticfile on STATICFIELS_DIRS.
  3. I use sass to generate CSS, So I need to generate css in build_files. Be aware of change direction.
## build_files.sh

cd static                   # My project use SASS to generate CSS files. The path is  '/<PROJECT_NAME>/static'                                                                                
npm install -y          # I Have to change dir to generate CSS   
npm run sass    
cd -                           # Back on root dir
pip install -r requirements.txt --user 
python3.9 manage.py collectstatic --no-input    # Your have to collect static file for the project. the files will be on '/vercel/path0/<STATIC_ROOT>'

npm run sass is mean sass scss:css

## static/package.json

........
  "scripts": {
     "sass": "sass scss:css"
  },
.......

Step 3: Configure Django project

I use ENV variable and django-environ to manange environ of runtime. so it will be a little diffrence from you. You don't have to be surprised.

  1. We allow "*.vercel.app" subdomains in ALLOWED_HOSTS, in addition to 127.0.0.1:

3.1 configure settings.py

## settings.py
if ENV := os.environ.get("ENV") and ENV in ('dev', 'test', 'live', 'vercel'):
    if ENV == "dev"
        .................
        )
    elif ENV == "test":
        env = environ.Env(
        ................
        )
    elif ENV == "live":
        env = environ.Env(
        ............
        )
    elif ENV == "vercel":
        env = environ.Env(
            DEBUG=(bool, True),
            HOSTS=(
                list,
                (
                    "127.0.0.1",
                    "localhost",
                    ".vercel.app",
                    ".now.sh",
                ),
            ),
            SECRET_KEY=(str, os.environ.get("SECRET_KEY")),
            SQLITE=("db", os.environ.get("DB")), 
            STATIC_ROOT=(str, BASE_DIR / "vercel" / "static/"),
            MEDIA_ROOT=(str, BASE_DIR / "vercel" / "media/"),
        )
else:
    raise Exception(
        """Please set system variable of ENV before running django.
        \n
        Example: export ENV='dev'
        \n
        """
    )

3.2 Add public var for WSGI application

Add app = get_wsgi_application() to the bottom of the <your_projecte>/wsgi.py.

The wsgi module must use a public variable named app to expose the WSGI application:

3.3 Configure STATIC URL for static files

import os
........
from django.conf import settings
from django.conf.urls.static import static


urlpatterns = [ 
    path("admin/", admin.site.urls),
    ..........
]


if ENV := os.environ.get("ENV") == "vercel":
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)