Skip to content

Environment variables

All runtime configuration is read from environment variables. The canonical reference is backend/.env.example in the repository. Copy it and edit:

cd backend
cp .env.example .env

Required

Variable Default Description
SECRET_KEY dev placeholder Django's signing key, and it also signs every JWT. Startup fails outside dev if it is left at the placeholder. It must be at least 32 bytes: HS256 needs a key as long as its hash, and a shorter one only produces a warning nobody reads. Changing it signs everybody out.
ENV_TYPE dev dev or prod. Controls where media is written and which security checks are enforced at startup.
DEBUG True Set to False in production.
ALLOWED_HOSTS localhost,127.0.0.1 Comma-separated.
FRONTEND_URL http://localhost:5173 The web app's base URL, and the one setting that carries every link this system emails: magic-link sign-in, the customer's invoice and estimate portal links, the CSAT survey, and internal assignment notices. Outside dev a loopback value is refused at startup, because left at the default it mails your customers a link to their own machine.

Database

There is no DATABASE_URL. The connection is assembled from five separate variables:

Variable Default
DBNAME crm_db
DBUSER postgres
DBPASSWORD postgres
DBHOST localhost
DBPORT 5432

PostgreSQL only, and the application user must not be a Postgres superuser. Superusers bypass row-level security, which is what isolates one organisation's rows from another's. See Postgres + RLS.

Connection pooling

Variable Default Description
DB_POOL_ENABLED False Turn on psycopg's connection pool.
DB_POOL_MIN_SIZE 2
DB_POOL_MAX_SIZE 10

CONN_MAX_AGE is pinned to 0 because Django refuses a non-zero value alongside a pool.

Celery

Variable Default
CELERY_BROKER_URL redis://localhost:6379/0
CELERY_RESULT_BACKEND redis://localhost:6379/0

Not optional if you want the scheduled work: recurring invoices, overdue marking, payment reminders, expired estimates, SLA breach scanning and stale-timer cleanup are all periodic jobs. Without a worker and a beat process, those features are silently inert.

Email

Variable Default Description
EMAIL_BACKEND console backend Use django_ses.SESBackend for AWS SES.
DEFAULT_FROM_EMAIL noreply@localhost
ADMIN_EMAIL admin@localhost
AWS_SES_REGION_NAME ap-south-1 Read only when the backend is SES.
AWS_SES_REGION_ENDPOINT derived from the region

SES falls back to IAM role credentials if AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are unset. For plain SMTP, set EMAIL_BACKEND to Django's SMTP backend and add Django's own EMAIL_HOST family; the project does not define those itself.

Google OAuth

Variable Description
GOOGLE_CLIENT_ID Leave blank to disable Google sign-in.
GOOGLE_CLIENT_SECRET

Magic-link sign-in works without either, so OAuth is genuinely optional.

CORS, CSRF and proxies

Variable Default Description
CORS_ALLOWED_ORIGINS dev origins Comma-separated.
CORS_ALLOW_ALL False Do not enable in production.
CSRF_TRUSTED_ORIGINS dev origin
TRUST_PROXY_SSL_HEADER False Set to True only when TLS terminates at a proxy that is the only way in. It makes Django trust X-Forwarded-Proto, which is what lets HSTS emit a header at all. On direct HTTP it becomes a value any caller can forge.
DOMAIN_NAME http://localhost:8000 The API's own origin.

Frontend

The SvelteKit app reads two variables, and neither is named what this page used to claim:

Variable Description
PUBLIC_DJANGO_API_URL Base URL of the Django backend.
PUBLIC_SENTRY_DSN Optional error reporting.

Anything prefixed PUBLIC_ is shipped to the browser. Never put a secret there.

Media and attachments

Files are written to the local filesystem under media/, always. There is no S3 or object-storage backend: the project configures no STORAGES or DEFAULT_FILE_STORAGE, so AWS_BUCKET_NAME in the example file is currently inert for uploads and the AWS keys matter only for SES. If you need object storage, that is a change to the Django settings rather than an environment variable.

A single attachment is capped at 25 MB, and CSV imports and lead uploads at 5 MB.

Corrections

This page previously documented DJANGO_SECRET_KEY, JWT_SIGNING_KEY, DATABASE_URL, REDIS_URL, EMAIL_HOST, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, EMAIL_PORT, GOOGLE_REDIRECT_URI, AWS_STORAGE_BUCKET_NAME, AWS_S3_ENDPOINT_URL, PUBLIC_API_URL and PUBLIC_GOOGLE_CLIENT_ID, and pointed at a .env.docker.example file. None of those names is read by crm/settings.py and that file does not exist, so anyone configuring a deployment from this page could not have started the application. Kept as a note rather than deleted, so somebody debugging a .env written from the old version can see what happened.