What Claude Code or Cursor has to change when you ask it to deploy an existing Django project to AWS with Postgres, done by hand on ECS and RDS, and with Encore added to the project as an infrastructure SDK.
A Django project that runs with manage.py runserver on a laptop is a long way from one that serves traffic on AWS.
When you ask an agent to deploy it, the agent has to pick a place to run the container, give it a Postgres database it can reach, move secrets out of settings.py, as the twelve-factor app recommends for config, and work through Django's deployment checklist, which covers DEBUG, SECRET_KEY, ALLOWED_HOSTS and HTTPS settings among others. Each of those is a place where a model can produce something that looks right and fails on the first request.
This guide compares the two routes an agent can take with an existing project, keeping the Django code itself the same in both.
The common AWS layout for Django is a container on ECS with Fargate behind a load balancer, with Postgres on RDS. In settings the agent replaces hard-coded values with environment variables:
import os
DEBUG = os.environ.get("DJANGO_DEBUG") == "1"
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
ALLOWED_HOSTS = os.environ["DJANGO_ALLOWED_HOSTS"].split(",")
# Injected into the ECS task from Secrets Manager and the task definition.
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ["DB_NAME"],
"USER": os.environ["DB_USER"],
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": os.environ["DB_HOST"],
"PORT": os.environ.get("DB_PORT", "5432"),
"CONN_MAX_AGE": 60,
}
}
Then it writes the infrastructure: an ECR repository and a Dockerfile, an ECS cluster and service, an Application Load Balancer, the RDS instance in private subnets, and task definitions that pull the password from Secrets Manager with an execution role allowed to read it. python manage.py migrate also needs somewhere to run, usually a one-off ECS task before the new version takes traffic. This setup gives full control and is well documented, and it is a lot of surface for an agent to get right without a real AWS account to test against.
Encore combines an open source infrastructure SDK, which the Django project imports for its database and other resources, with a platform that provisions those resources in your own AWS account. Django keeps its ORM, admin, URL routing and migrations. The changes below come from the Django example in the Encore SDK repository.
The project adds encore-dev and psycopg to its dependencies:
[project]
name = "django-hello-world"
version = "0.1.0"
requires-python = ">=3.14"
dependencies = [
"django>=5.2,<6",
"encore-dev",
"psycopg[binary]>=3.2",
]
Note that the example sets requires-python = ">=3.14", so a project on an older Python needs an upgrade before it matches this setup.
An encore.service.json in the project root names the service and exposes its routes:
{
"name": "django_hello_world",
"lang": "python",
"api": [
{ "type": "http", "prefix": "/", "name": "django_hello_world", "expose": true }
]
}
The database and an object storage bucket are declared in a module of their own. Django still owns the schema, so no migrations directory is passed:
"""Encore discovers this declaration and provisions storage and PostgreSQL."""
from encore.storage import objects
from encore.storage import postgres
uploads = objects.Bucket("uploads")
# Django manages the schema through its own migrations.
db = postgres.Database("django")
settings.py builds DATABASES from the connection string the SDK provides, parsed with psycopg's conninfo helpers so escaping and options are preserved:
from psycopg.conninfo import conninfo_to_dict
from storage.resources import db
connection = conninfo_to_dict(db.connection_string)
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": connection.pop("dbname"),
"USER": connection.pop("user", ""),
"PASSWORD": connection.pop("password", ""),
"HOST": connection.pop("host", ""),
"PORT": connection.pop("port", ""),
"OPTIONS": connection,
}
}
A small main.py adapts Encore's listen address to Django's development server, and installs Encore's tracing, metrics and log handler:
"""Adapt Encore's listen address to Django's development server."""
import logging
import os
from django.core.management import execute_from_command_line
from encore.logs import ConsoleHandler
from encore.metrics import meter_provider
from encore.tracing import tracer_provider
from opentelemetry import metrics, trace
from opentelemetry.instrumentation.django import DjangoInstrumentor
def main() -> None:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
trace.set_tracer_provider(tracer_provider())
metrics.set_meter_provider(meter_provider())
DjangoInstrumentor().instrument()
logging.basicConfig(level=logging.INFO, handlers=[ConsoleHandler()])
address = os.environ.get("ENCORE_LISTEN_ADDR", "127.0.0.1:8000")
# Encore restarts the service on changes; a second reloader is unnecessary.
execute_from_command_line(["manage.py", "runserver", address, "--noreload"])
if __name__ == "__main__":
main()
encore run starts Postgres locally and runs the project against it. Management commands run through encore exec, so the SDK receives its runtime configuration:
encore exec -- uv run python manage.py migrate
encore exec -- uv run python manage.py createsuperuser
The agent can then open the admin and call views before anything is deployed, which lets it catch a broken setting itself before it hands the change over.
On deploy, Encore provisions the database and compute in your AWS account.
Encore does not run Django migrations. Django owns the schema, so run migrate as a release step before the new version serves ORM endpoints. The runserver adapter in main.py is for local development, and this guide does not cover a production server setup.
Instance size, backups, networking and scaling are set per environment rather than in the Django code. The agent changes Python files, and cloud access sits with Encore's IAM role, not the agent.
Only admins can approve new infrastructure when a declaration adds a resource.
The settings from Django's checklist still apply. DEBUG should come from the environment rather than the file, as in the hand-built route. SECRET_KEY can come from an Encore secret, since the Python SDK supports secrets:
from encore.secrets import Secret
django_secret_key = Secret[str]("DjangoSecretKey")
SECRET_KEY = django_secret_key.value
The value is set per environment with encore secret set, outside the repo. Encore supports Postgres, so a project on MySQL keeps its own database setup.
With Encore, the agent adds the encore-dev package, an encore.service.json and a small main.py adapter, declares the database with postgres.Database and builds DATABASES from its connection string. encore run starts Postgres locally, and Encore provisions the database and compute in your AWS account on deploy. Without Encore, the agent writes a Dockerfile, an ECS service, an RDS instance, Secrets Manager entries and IAM roles, and reads them in settings.py through environment variables.
No. Django keeps its ORM, admin, migrations and URL routing. Encore is an infrastructure SDK added to the project, so it supplies the database connection and other resources and handles provisioning and deploys.
Django's deployment checklist covers DEBUG, SECRET_KEY, ALLOWED_HOSTS and the HTTPS settings. With Encore, those values still live in settings.py and should come from the environment or secrets, and cloud access sits with Encore's IAM role, not the agent.
Deploy to your cloud on AWS and Google Cloud
without managing infrastructure
Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.