Environment variables
Complete reference for every environment variable across the NexSchool services (server, admin-web, panel, client) and the deployment infrastructure.
All environment files live in school-erp-infra/env/:
| File | Purpose |
|---|---|
.env.local.example | Template for local development |
.env.local | Local dev secrets (never commit) |
.env.prod.example | Template for production |
.env.prod | Production secrets (never commit, lives on EC2) |
Never commit secrets
- Never commit
.env.localor.env.prodto git. Only commit.env.*.examplefiles with placeholder values. - If a secret is accidentally committed, rotate it immediately — removing it from the next commit is not enough, because git history retains it.
- The tables below use placeholders such as
<set-in-secrets-manager>wherever the source held a real-looking secret. Never paste actual credentials into docs, examples, or committed files. JWT_SECRETandSECRET_KEYmust be cryptographically random strings of at least 32 characters in production.- Production
DATABASE_URLmust only be reachable from the EC2 security group (RDS private subnet).
Backend (server/)
| Variable | Purpose | Required? | Default/example |
|---|---|---|---|
DATABASE_URL | SQLAlchemy connection string | Yes | postgresql://user:pass@postgres:5432/school_erp |
REDIS_URL | General cache backend | Yes | redis://redis:6379/0 |
CELERY_BROKER_URL | Celery task queue broker | Yes | redis://redis:6379/0 |
CELERY_RESULT_BACKEND | Celery result storage | Yes | redis://redis:6379/0 |
JWT_SECRET | Signs JWT access tokens | Yes | <set-in-secrets-manager> |
JWT_REFRESH_SECRET | Signs refresh tokens (may reuse JWT_SECRET) | No | <set-in-secrets-manager> |
SECRET_KEY | Flask session secret | Yes | <set-in-secrets-manager> |
FLASK_ENV | Controls debug mode | Yes | development / production |
FLASK_APP | Flask app entry (for CLI) | No | app:create_app |
DEFAULT_TENANT_SUBDOMAIN | Fallback tenant for local dev | No | demo |
ALLOWED_ORIGINS | CORS allowed origins | No | http://localhost,http://panel.localhost |
AWS_ACCESS_KEY_ID | S3 file uploads | No | <set-in-secrets-manager> |
AWS_SECRET_ACCESS_KEY | S3 file uploads | No | <set-in-secrets-manager> |
AWS_S3_BUCKET | S3 bucket name | No | nexschool-uploads |
AWS_REGION | S3 region | No | ap-south-1 |
CLOUDINARY_URL | Student document storage | No | cloudinary://<set-in-secrets-manager> |
CLOUDINARY_CLOUD_NAME | Cloudinary cloud | No | nexschool |
CLOUDINARY_API_KEY | Cloudinary API key | No | <set-in-secrets-manager> |
CLOUDINARY_API_SECRET | Cloudinary API secret | No | <set-in-secrets-manager> |
MAIL_SERVER | SMTP server for emails | No | smtp.gmail.com |
MAIL_PORT | SMTP port | No | 587 |
MAIL_USERNAME | SMTP user | No | noreply@nexschool.com |
MAIL_PASSWORD | SMTP password | No | <set-in-secrets-manager> |
MAIL_USE_TLS | TLS for email | No | true |
FIREBASE_CREDENTIALS_JSON | Firebase Admin SDK JSON (push notifications) | No | <set-in-secrets-manager> |
MAX_CONTENT_LENGTH | Max upload size in bytes (64 MB default); keep in sync with nginx client_max_body_size | No | 67108864 |
GUNICORN_THREADS | gthread pool size per worker; must exceed peak concurrent SSE streams | No | 16 |
LOG_LEVEL | Logging level | No | INFO |
Admin Web (admin-web/)
Only NEXT_PUBLIC_* vars are accessible in browser code. Others are server-side only.
| Variable | Purpose | Required? | Default/example |
|---|---|---|---|
ADMIN_WEB_BASE_URL | Base URL used to build password-reset and login links. Set this in production — see the callout below. | Yes (prod) | https://<tenant>.nexschool.com |
NEXT_PUBLIC_API_URL | Base URL for all API calls | Yes | http://localhost/api |
NEXT_PUBLIC_GATEWAY_ORIGIN | Browser-facing origin | Yes | http://localhost |
NEXT_PUBLIC_PANEL_URL | Link to super-admin panel | No | http://panel.localhost |
NEXT_PUBLIC_FIREBASE_API_KEY | Firebase web app config | No | <set-in-secrets-manager> |
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN | Firebase auth domain | No | project.firebaseapp.com |
NEXT_PUBLIC_FIREBASE_PROJECT_ID | Firebase project | No | nexschool-prod |
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET | Firebase storage | No | nexschool-prod.appspot.com |
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID | Firebase messaging | No | 123456789 |
NEXT_PUBLIC_FIREBASE_APP_ID | Firebase app ID | No | 1:123:web:abc |
NEXT_PUBLIC_FIREBASE_VAPID_KEY | Web push VAPID key | No | <set-in-secrets-manager> |
Set
ADMIN_WEB_BASE_URLin production. Password-reset and login links are generated from this base URL. If it is unset, links fall back tolocalhostand will not work for real users. Point it at the tenant-facing admin-web origin before enabling password reset or login-link flows.
Super-admin Panel (panel/)
| Variable | Purpose | Required? | Default/example |
|---|---|---|---|
NEXT_PUBLIC_API_URL | Same API as admin-web | Yes | http://localhost/api |
NEXT_PUBLIC_GATEWAY_ORIGIN | Panel’s own origin | Yes | http://panel.localhost |
Mobile App (client/)
Expo uses .env or app.config.js. Variables must be prefixed EXPO_PUBLIC_ to be accessible in app code.
| Variable | Purpose | Required? | Default/example |
|---|---|---|---|
EXPO_PUBLIC_API_URL | LAN IP for physical device | Yes | http://192.168.1.x/api |
EXPO_PUBLIC_TENANT_SUBDOMAIN | Default tenant for dev | No | demo |
Docker Compose (infra)
Set in school-erp-infra/env/.env.local or .env.prod. Compose substitutes these into service configs.
| Variable | Purpose | Required? | Default/example |
|---|---|---|---|
ECR_API_URL | Full ECR image URL for API (prod compose) | Yes (prod) | <account>.dkr.ecr.ap-south-1.amazonaws.com/nexschool-api |
ECR_ADMIN_WEB_URL | Full ECR image URL for admin-web (prod compose) | Yes (prod) | <account>.dkr.ecr.ap-south-1.amazonaws.com/nexschool-admin-web |
ECR_PANEL_URL | Full ECR image URL for panel (prod compose) | Yes (prod) | <account>.dkr.ecr.ap-south-1.amazonaws.com/nexschool-panel |
POSTGRES_USER | DB user (postgres service) | Yes | <set-in-secrets-manager> |
POSTGRES_PASSWORD | DB password (postgres service) | Yes | <set-in-secrets-manager> |
POSTGRES_DB | DB name (postgres service) | Yes | school_erp |
GitHub Actions secrets
Configured in the repository/organization secrets store, not in .env files. Consumed by the deploy workflows.
| Secret | Purpose | Required? | Default/example |
|---|---|---|---|
AWS_ROLE_TO_ASSUME | OIDC role for all deploy workflows | Yes | <set-in-secrets-manager> |
EC2_HOST | SSH hostname/IP for deploy SSH step | Yes | <set-in-secrets-manager> |
EC2_SSH_PRIVATE_KEY | PEM key for EC2 SSH | Yes | <set-in-secrets-manager> |
ECR_REPO_SERVER | ECR repository URI for API image | Yes | <set-in-secrets-manager> |
ECR_REPO_ADMIN_WEB | ECR repository URI for admin-web image | Yes | <set-in-secrets-manager> |
ECR_REPO_PANEL | ECR repository URI for panel image | Yes | <set-in-secrets-manager> |
NEXT_PUBLIC_API_URL | Build-time var for Next.js images | Yes | <set-in-secrets-manager> |
NEXT_PUBLIC_FIREBASE_* | Build-time Firebase config for admin-web | No | <set-in-secrets-manager> |