Deploy Django on Google App Engine (Standard, Cloud SQL & Cloud Run)

Blog / Server Management · December 2, 2014 · Updated June 10, 2026 · 8 min read
Deploy Django on Google App Engine (Standard, Cloud SQL & Cloud Run)

In 2026, deploying Django on Google App Engine means using App Engine Standard (2nd generation) on a Python 3.x runtime, where standard Django runs natively. You point an app.yaml at a gunicorn entrypoint, keep your relational data in Cloud SQL (PostgreSQL or MySQL) connected over a unix socket via the Cloud SQL Auth Proxy, serve static files with WhiteNoise, store user uploads in Cloud Storage, then ship with gcloud app deploy. The approach this article once described — the Python 2.7 sandbox, django-nonrel, and using Datastore as the Django database — is dead and should not be used. For many new projects, Cloud Run (containerized, scales to zero) is now the more flexible way to run Django on GCP.

Key takeaways

  • App Engine Standard now runs real Django. The 2nd-gen Python 3 runtime drops the old sandbox restrictions, so unmodified Django works without hacks.
  • django-nonrel is obsolete. You no longer bend Django onto Datastore — use Cloud SQL (PostgreSQL or MySQL) as a normal relational database.
  • Connect through the Cloud SQL Auth Proxy. On App Engine the database is reached over a unix socket at /cloudsql/<connection-name>; locally you tunnel through the proxy.
  • Static and media files go elsewhere. Serve static assets with WhiteNoise (bundled in the app) and store user uploads in a Cloud Storage bucket via django-storages.
  • Run migrations yourself. App Engine has no SSH, so you run migrate from your machine through the Cloud SQL Auth Proxy.
  • Consider Cloud Run. A container that scales to zero is often a better fit than App Engine for new Django apps, and it supports WebSockets and long-running requests.

What changed since the old GAE + django-nonrel era?

When this post was first written, App Engine only offered the Python 2.7 standard sandbox. That sandbox blocked arbitrary system calls, banned many C extensions, and shipped no relational database — so the community used django-nonrel to force Django's ORM onto the schemaless Datastore. It worked, but it was fragile: no joins, no migrations, and constant fights with Django internals.

All of that is gone:

  • Python 2.7 reached end of life in 2020 and the 1st-gen sandbox is retired. The 2nd-gen runtimes (python39 through python312) run on gVisor with far fewer restrictions.
  • django-nonrel is unmaintained. Modern Django expects a real SQL backend, and you get one with Cloud SQL.
  • Datastore is no longer your primary DB. Firestore in Datastore mode still exists for NoSQL needs, but standard Django uses PostgreSQL or MySQL on Cloud SQL.

If you find a tutorial mentioning python27, threadsafe: true, django-nonrel, or a main.application WSGI shim, treat it as historical — none of it applies to a 2026 deployment.

Which GCP runtime should you use for Django?

GCP gives you three realistic homes for a Django app. App Engine Standard is the simplest managed option, App Engine Flexible runs your own Docker image on a managed VM, and Cloud Run runs any container and scales to zero.

Capability App Engine Standard (2nd gen) App Engine Flexible Cloud Run
Packaging Source + app.yaml (managed runtime) Custom Dockerfile on a managed VM Any container image
Scales to zero Yes No (minimum 1 instance) Yes
Cold starts Low Higher (VM boot) Low to moderate
WebSockets / streaming Not supported Supported Supported
Max request timeout Short (minutes) Longer Up to 60 minutes
Best for Standard Django apps wanting the simplest deploy Apps needing custom OS packages Most new, containerized Django apps

Rule of thumb: choose App Engine Standard when you want a managed runtime and no Dockerfile, Flexible when you need custom system packages but still want App Engine, and Cloud Run when you want a portable container, WebSockets, or longer requests. The rest of this guide focuses on App Engine Standard, since that is what "Django on GAE" means.

How do you configure app.yaml for Django on App Engine Standard?

A modern deployment needs just two files at your project root: a requirements.txt and an app.yaml. The app.yaml selects the Python 3 runtime, defines a gunicorn entrypoint that points at your project's WSGI module, declares the Cloud SQL instance, and passes configuration through environment variables.

First, the dependencies:

# requirements.txt
Django>=5.0,<5.2
gunicorn
psycopg2-binary          # PostgreSQL driver
whitenoise               # serve static files from the app
django-storages[google]  # media uploads to Cloud Storage

Then the app.yaml that App Engine reads on deploy:

# app.yaml  (App Engine Standard, 2nd generation)
runtime: python312

# gunicorn serves the WSGI app on the port App Engine provides
entrypoint: gunicorn -b :$PORT myproject.wsgi:application

# Expose the Cloud SQL instance to the app over a unix socket
beta_settings:
  cloud_sql_instances: "my-project:us-central1:my-instance"

env_variables:
  DJANGO_SETTINGS_MODULE: "myproject.settings"
  CLOUD_SQL_CONNECTION_NAME: "my-project:us-central1:my-instance"
  DB_NAME: "mydb"
  DB_USER: "django"
  # In production, pull secrets from Secret Manager rather than hard-coding them
  DB_PASSWORD: "set-via-secret-manager"

handlers:
# Let WhiteNoise (inside the app) serve everything; no script: main.application shim
- url: /.*
  script: auto

How do you connect Django to Cloud SQL?

Django talks to Cloud SQL like any PostgreSQL database — the only twist is how it connects. On App Engine the instance is exposed as a unix socket at /cloudsql/<connection-name>, so you set HOST to that path. On your laptop you instead run the Cloud SQL Auth Proxy and connect to 127.0.0.1. Detect which environment you are in with the GAE_APPLICATION variable that App Engine sets automatically.

# settings.py
import os

if os.getenv('GAE_APPLICATION', None):
    # Running on App Engine: connect over the Cloud SQL unix socket
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'HOST': '/cloudsql/' + os.environ['CLOUD_SQL_CONNECTION_NAME'],
            'NAME': os.environ['DB_NAME'],
            'USER': os.environ['DB_USER'],
            'PASSWORD': os.environ['DB_PASSWORD'],
        }
    }
else:
    # Local dev: connect through the Cloud SQL Auth Proxy on 127.0.0.1:5432
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql',
            'HOST': '127.0.0.1',
            'PORT': '5432',
            'NAME': os.environ['DB_NAME'],
            'USER': os.environ['DB_USER'],
            'PASSWORD': os.environ['DB_PASSWORD'],
        }
    }

ALLOWED_HOSTS = ['*']  # narrow this to your appspot.com and custom domains

How do you serve static and media files?

App Engine Standard has no persistent disk and no separate web server you control, so you split the two cases. Static files (CSS, JS, admin assets) are bundled into the deploy and served by WhiteNoise straight from the app. Media files (user uploads) must live in Cloud Storage, because anything written to the instance disk disappears when it scales or restarts.

# settings.py (static via WhiteNoise, media via Cloud Storage)
import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',  # right after SecurityMiddleware
    # ... the rest of your middleware
]

STORAGES = {
    # Compressed, hashed static files served by WhiteNoise
    'staticfiles': {
        'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage',
    },
    # User uploads persisted in a Cloud Storage bucket
    'default': {
        'BACKEND': 'storages.backends.gcloud.GoogleCloudStorage',
        'OPTIONS': {'bucket_name': 'my-app-media'},
    },
}

How do you deploy and run migrations?

Deploying is one command. Migrations are the part people miss: App Engine instances have no SSH, so you cannot run manage.py migrate on the server. Instead you collect static files, deploy the code, then run migrations from your own machine through the Cloud SQL Auth Proxy pointed at the same instance.

# 1. Authenticate and select your project
gcloud auth login
gcloud config set project my-project

# 2. Collect static files so WhiteNoise can serve them
python manage.py collectstatic --noinput

# 3. Deploy to App Engine Standard
gcloud app deploy app.yaml

# 4. Run migrations through the Cloud SQL Auth Proxy (separate terminal)
./cloud-sql-proxy my-project:us-central1:my-instance &
python manage.py migrate

# 5. Open the live app (https://your-app-id.<region>.r.appspot.com)
gcloud app browse

What about other hosts and migrating off old GAE?

App Engine is not the only managed home for Django. Heroku is a popular PaaS alternative with a similar git-style workflow — see our companion guide on deploying your Django app on Heroku to compare the two. Cloud Run is the GCP option to reach for when you need WebSockets, longer requests, or a portable container.

If you are stuck on the legacy Python 2.7 / django-nonrel setup, the path forward is to move the data off Datastore into Cloud SQL and re-platform onto a 2nd-gen runtime. That is exactly the kind of re-hosting our cloud migration services handle — lifting an aging app onto modern GCP infrastructure without a rewrite.

Frequently Asked Questions

Can you still run Django on Google App Engine in 2026?

Yes. App Engine Standard (2nd generation) runs Python 3.x, and standard, unmodified Django runs on it natively. You define a gunicorn entrypoint in app.yaml, connect to Cloud SQL for your database, and deploy with gcloud app deploy. The only thing that is gone is the old Python 2.7 sandbox model.

Do I still need django-nonrel for App Engine?

No. django-nonrel and the practice of using Datastore as the Django database are obsolete and unmaintained. Modern deployments use Cloud SQL (PostgreSQL or MySQL) as a normal relational backend, so Django's ORM, joins, and migrations all work as designed.

Should I use App Engine or Cloud Run for Django?

Use App Engine Standard when you want a fully managed runtime with no Dockerfile. Choose Cloud Run when you need a portable container, WebSockets, or longer request timeouts — it also scales to zero. For many new Django projects on GCP, Cloud Run is now the more flexible default.

How does Django connect to the database on App Engine?

On App Engine the Cloud SQL instance is exposed over a unix socket at /cloudsql/<connection-name>, so you set the database HOST to that path. Locally you run the Cloud SQL Auth Proxy and connect to 127.0.0.1. A check on the GAE_APPLICATION environment variable lets one settings file handle both.

How do I run database migrations on App Engine?

App Engine instances have no SSH, so you cannot run migrations on the server. Start the Cloud SQL Auth Proxy on your own machine pointed at the production instance, then run python manage.py migrate locally against it. Run collectstatic before deploying so WhiteNoise can serve your assets.

Where should static and media files live?

Serve static files (CSS, JS, admin assets) with WhiteNoise, which bundles them into the deploy and serves them from the app. Store media — user uploads — in a Cloud Storage bucket through django-storages, because anything written to an instance's local disk is lost when it scales or restarts.

Share this article