Environment variables
A one-to-one reference for every Didacta environment variable, grouped by area. The commented template lives in the repository's .env.example.
"Component" legend: api = NestJS (apps/api) · web = Next.js (apps/web) · worker = BullMQ workers inside the API process · compose = read only by Docker Compose · build = image build only · tests = test/E2E suites.
Operational summary
Minimum to start (the app fails or degrades badly without them):
ADMIN_DATABASE_URL (or DATABASE_URL as a fallback — see § Database)
REDIS_URL
AUTH_SECRET — the only one that causes a hard crash at startup if missing or shorter than 32 characters.
With docker-compose.alpha.yml the first two are composed automatically: only AUTH_SECRET is required.
Strongly recommended in production:
WEB_PUBLIC_URL — without it, every email carries links to localhost.
TENANT_SETTINGS_ENC_KEY — set it before configuring OIDC SSO, per-tenant SMTP, Stripe or Zoom S2S.
METRICS_TOKEN — if /metrics is reachable from the internet.
AUDIT_REPORT_HMAC_KEY — the embedded fallback is public (it is in the repository).
WEB_PUBLIC_ALLOWED_HOSTS — if SSO is enabled.
POSTGRES_PASSWORD and MINIO_ROOT_PASSWORD set to something other than the didacta_dev default.
1. Core / application
| Name |
Required |
Default |
Component |
Description |
NODE_ENV |
No |
production |
api, web, compose |
Execution mode. Controls the Pino logger level (info in production, debug elsewhere). With test, BullMQ workers and telemetry are disabled. DIDACTA_DEV_BYPASS is ignored when this is production. |
API_PORT |
No |
4000 |
api, compose |
Port of the NestJS API. In docker-compose.alpha.yml the internal port is pinned to 4000 and this variable only controls the host mapping. |
WEB_PORT |
No |
3000 |
web, compose |
Next.js port. Same as API_PORT: in the alpha compose file it only maps the host port. |
DIDACTA_IMAGE_TAG |
No |
the repository's recommended version |
compose |
Tag of the ghcr.io/va360labs/didacta-community image the compose file brings up. Always pin a specific version. |
DIDACTA_CORE_VERSION |
No |
derived from the build / DIDACTA_IMAGE_TAG |
api, compose |
Source of truth for the core version: consumed by /healthz, by marketplace module compatibility validation and by telemetry. Not normally touched. |
RLS_ENFORCEMENT |
No |
on |
api |
Row-Level Security enforcement at runtime: off | warn | on. In warn/on, every query with a tenant context travels with set_config('app.current_tenant_id'); queries without a context are logged at warning (warn) or error (on) level. Isolation is real because DATABASE_URL connects with the didacta_app role (without BYPASSRLS) by default — see § Database. |
LOG_DB_QUERIES |
No |
— |
api |
With true, Prisma logs every SQL query. Very verbose; debugging only. |
DIDACTA_CNAME_TARGET |
No |
cname.didacta.io |
api |
CNAME target shown to the admin by the custom domains UI. |
2. Public URLs and API ↔ Web routing
| Name |
Required |
Default |
Component |
Description |
WEB_PUBLIC_URL |
Strongly recommended in prod |
cascade (see note) |
api, worker |
Public base URL of the frontend. It builds every absolute link in emails (password resets, invitations, reminders, digests…). Cascade: this variable → the request's X-Forwarded-* headers → http://localhost:3000. |
WEB_PUBLIC_ALLOWED_HOSTS |
No |
— |
api |
CSV allowlist of hosts for redirects that carry session tokens (SSO / WP-SSO callbacks). Without it, the request host is never used to redirect tokens — it protects against open redirects. Format: domain1.com,domain2.com. |
PUBLIC_API_URL |
No |
falls back to the web base |
api |
Public base URL of the API. Used by branded emails (assets/logos served from the API) and as a fallback for the OIDC redirect_uri and the SAML URLs. |
PUBLIC_BASE_URL |
No |
'' (relative path) |
api |
Absolute base that local storage prefixes to /api/v1/storage/file/… so file URLs are absolute. |
WEB_BASE_URL |
No |
http://localhost:3000 |
api |
Base URL injected into the ModuleContext of marketplace modules. Different from WEB_PUBLIC_URL (which belongs to the core). |
API_INTERNAL_URL |
No |
http://localhost:4000 |
web |
Internal API URL used by the Next.js rewrites, server-side fetch and middleware. In the browser the same origin is always used — no CORS. |
NEXTAUTH_URL |
No |
— |
api |
A NextAuth legacy; only the second fallback for the web base in OIDC/SAML. Do not use it in new installations. |
The frontend exposes no variables to the browser
Didacta uses no NEXT_PUBLIC_* variables of its own in the client bundle: all web configuration is server-side and the browser always talks to its own origin thanks to the Next.js rewrites.
3. Database (PostgreSQL)
| Name |
Required |
Default |
Component |
Description |
ADMIN_DATABASE_URL |
Yes (or DATABASE_URL as a fallback) |
— |
api, worker, compose |
The administration connection (superuser/owner): postgresql://user:pass@host:port/db?schema=public. The entrypoint uses it ONLY for migrations + rls.sql + grants.sql — never to serve traffic. In the alpha compose file it is built automatically from POSTGRES_*. |
DATABASE_URL |
No — leave it empty |
derived from ADMIN_DATABASE_URL |
api, worker, compose |
The app's runtime connection. If you leave it empty (the normal case), the entrypoint derives it by swapping the username/password of ADMIN_DATABASE_URL for the didacta_app role (without BYPASSRLS — real RLS isolation). If you set it explicitly, it is honoured as is (upgrade path: existing installations that only had this variable pointing at the superuser still start, with a logged degradation). |
POSTGRES_USER |
No |
didacta |
compose |
User of the Postgres container (the one in ADMIN_DATABASE_URL). |
POSTGRES_PASSWORD |
No |
didacta_dev |
compose |
Password of the Postgres container. Change it in any non-local deployment (the compose file publishes Postgres on 127.0.0.1 only precisely because of this default). |
POSTGRES_DB |
No |
didacta |
compose |
Database name. |
POSTGRES_PORT |
No |
5432 |
compose |
Host port mapped to Postgres (published on loopback only). |
POSTGRES_APP_PASSWORD |
No |
auto-generated and persisted in the data volume |
compose |
Password of the didacta_app runtime role. If you leave it empty (the normal case), the entrypoint generates it once and persists it — you never need to know it. Set it only if you want to manage it from your secrets manager. |
4. Redis, queues and workers
| Name |
Required |
Default |
Component |
Description |
REDIS_URL |
Yes (in practice) |
— |
api, worker, compose |
Redis connection (redis://redis:6379). Without it, every BullMQ worker degrades silently (outbox, digests, broadcasts, GDPR purges, reminders…), along with distributed rate limiting, realtime messaging and SSE notifications. |
REDIS_PORT |
No |
6379 |
compose |
Host port mapped to Redis (loopback only: Redis runs without authentication). |
COMMUNITY_DIGEST_CRON |
No |
0 9 * * 1 |
worker |
Cron for the weekly community digest (Mondays at 09:00 UTC). |
COMMUNITY_BROADCAST_BATCH_SIZE |
No |
5 |
worker |
Recipients per batch in the community broadcast worker. |
COMMUNITY_BROADCAST_INTERVAL_MS |
No |
10000 |
worker |
Milliseconds between broadcast batches (anti-spam throttling for SMTP). |
LESSON_UNLOCK_CRON |
No |
*/10 * * * * |
worker |
Cron for the unlocked-lesson notifier (drip content). |
PAYMENT_SUBSCRIBERS_SYNC_CRON |
No |
*/15 * * * * |
worker |
Cron that syncs subscribers from the payment connections. |
REFERRALS_APPROVAL_CRON |
No |
30 * * * * |
worker |
Cron for automatic referral approval. |
SURVEYS_REMINDER_CRON |
No |
*/15 * * * * |
worker |
Cron for the post-class survey reminder. |
SURVEYS_REMINDER_DELAY_HOURS |
No |
24 |
worker |
Hours after the class before the survey reminder is sent. |
SURVEYS_HASH_SECRET |
No |
falls back to AUTH_SECRET |
api |
Secret used to hash identifiers in survey responses (anonymisation). |
5. Authentication, sessions and encryption
| Name |
Required |
Default |
Component |
Description |
AUTH_SECRET |
Yes |
— |
api, worker |
Signing secret for JWTs (access + refresh), enrollment tickets and unsubscribe tokens. At least 32 characters: the app throws at startup if it is missing or shorter. Generate it with openssl rand -base64 32. Changing it invalidates every session. |
AUTH_URL |
No |
https://didacta.local |
api |
JWT issuer (iss). Also the default base for Stripe checkout success/cancel URLs. |
AUTH_SIGNUP_ENABLED |
No |
false |
api, web |
Enables public sign-up (POST /auth/signup + the /signup page). Closed by design: real accounts come in through registration or an admin invitation. Only set it to true in dev/E2E stacks. |
TENANT_SETTINGS_ENC_KEY |
Critical if you use integrations |
— (cascade) |
api, compose |
AES-256 key, 64 hex characters, encrypting per-tenant secrets at rest (OIDC client secret, per-tenant SMTP, Stripe keys, Zoom S2S, Telegram bot; the SCIM token does not use it — only a SHA-256 hash of it is stored). Cascade: this variable → the ${STORAGE_ROOT}/.didacta-secret-key file (auto-generated, 0600) → an ephemeral in-memory key (secrets are lost on restart). Generate it with openssl rand -hex 32. Never rotate it without a re-encryption plan. |
TENANT_SETTINGS_ENC_KEY_FILE |
No |
${STORAGE_ROOT}/.didacta-secret-key |
api |
Alternative path for the master key file, so the key and the storage can live on different volumes. |
DIDACTA_REQUIRE_MFA_ADMIN |
No |
false |
api |
Forces MFA on admins across the whole instance. Accepts true/1/yes/on. Independent of the per-tenant policy (the feat:mfa.enforcement Enterprise capability). |
OIDC_REDIRECT_URI |
No |
falls back to PUBLIC_API_URL |
api |
The redirect_uri sent to the OIDC IdP; it must match the one registered with the provider. |
SAML_PUBLIC_API_URL |
No |
falls back to PUBLIC_API_URL |
api |
Public API base for the SAML ACS callback. |
SAML_SP_ENTITY_ID_BASE |
No |
<API base>/saml |
api |
Base of the SAML Service Provider entityID. |
RATE_LIMIT_COMMUNITY_AUTH_PER_MIN |
No |
100 |
api |
Requests per minute for authenticated users on the Community plan (Enterprise: 1000, not configurable). |
RATE_LIMIT_COMMUNITY_PUBLIC_PER_MIN |
No |
30 |
api |
Requests per minute for anonymous traffic on Community (Enterprise: 300). Fixed 60 s window. |
6. Email / SMTP
The first three work as a set: if any of SMTP_HOST, SMTP_PORT or SMTP_FROM is missing there is no instance-wide SMTP — only tenants with their own SMTP configured in the panel will send email.
| Name |
Required |
Default |
Component |
Description |
SMTP_HOST |
No |
mailpit in the compose file |
api, worker, compose |
Host of the instance-wide SMTP server. |
SMTP_PORT |
No |
1025 (Mailpit) |
api, compose |
SMTP port. |
SMTP_FROM |
No |
Didacta <noreply@didacta.local> |
api, compose |
Sender for every email. RFC format: Name <email@domain>. |
SMTP_USER |
No |
'' |
api |
SMTP authentication user. Empty = no auth (the Mailpit case). |
SMTP_PASS |
No |
'' |
api |
SMTP password (preferred name; the SMTP_PASSWORD alias exists for compatibility). |
SMTP_SECURE |
No |
decided by nodemailer from the port |
api |
Forces implicit TLS. Only the literals 'true'/'false' have any effect. |
MAILPIT_SMTP_PORT |
No |
1025 |
compose |
Host port of Mailpit's SMTP server. |
MAILPIT_UI_PORT |
No |
8025 |
compose |
Host port of the Mailpit UI (loopback only: it shows every message, password resets included). |
7. Object storage (local / S3 / MinIO)
| Name |
Required |
Default |
Component |
Description |
STORAGE_DRIVER |
No |
local in the compose file; auto-detection when unset |
api, compose |
local forces disk; s3 forces S3 (and fails at startup if S3_ENDPOINT/S3_BUCKET/S3_ACCESS_KEY/S3_SECRET_KEY are missing). When unset, it tries S3 and falls back to local if the configuration is incomplete. |
STORAGE_ROOT |
No |
/app/data/storage |
api, compose |
Root of the persistent volume: uploads (logos, certificates, SCORM, Fundae evidence) and the .didacta-secret-key master key. |
S3_ENDPOINT |
Yes, if you use S3 |
— |
api, compose |
S3-compatible endpoint (http://minio:9000, AWS, Hetzner…). |
S3_BUCKET |
Yes, if you use S3 |
— |
api |
Bucket name. |
S3_ACCESS_KEY |
Yes, if you use S3 |
— |
api |
Access key (accepted alias: S3_ACCESS_KEY_ID). |
S3_SECRET_KEY |
Yes, if you use S3 |
— |
api |
Secret key (accepted alias: S3_SECRET_ACCESS_KEY). |
S3_REGION |
No |
us-east-1 |
api |
Bucket region. |
S3_FORCE_PATH_STYLE |
No |
true |
api |
Path-style URLs (endpoint/bucket/key). Required for MinIO. |
S3_PRESIGNED_TTL_SECONDS |
No |
the SDK default |
api |
TTL in seconds of the presigned URLs. |
MINIO_ROOT_USER |
No |
didacta |
compose |
Root user of the MinIO container (the s3 profile). |
MINIO_ROOT_PASSWORD |
No |
didacta_dev |
compose |
MinIO root password. Change it outside local development. |
MINIO_API_PORT |
No |
9000 |
compose |
Host port of the MinIO S3 API. |
MINIO_CONSOLE_PORT |
No |
9001 |
compose |
Host port of the MinIO web console. |
8. AI — AI Gateway (BYOK)
The canonical AI configuration is per tenant, from the admin panel. These variables define the encryption key and the global fallback provider. The names in the DEFAULT_AI_* block are built by purpose: chat and embed.
| Name |
Required |
Default |
Component |
Description |
AI_CONFIG_ENCRYPTION_KEY |
Yes, to configure AI per tenant |
— |
api |
AES-256-GCM key encrypting per-tenant AI API keys. Exactly 64 hex characters or the module fails to initialise. One key per instance. |
DEFAULT_AI_CHAT_PROVIDER |
No |
— |
api |
Global default chat provider, used when a tenant has no configuration of its own. |
DEFAULT_AI_CHAT_API_KEY |
No |
— |
api |
API key of the global chat provider. |
DEFAULT_AI_CHAT_MODEL |
No |
'' |
api |
Default chat model. |
DEFAULT_AI_CHAT_BASE_URL |
No |
— |
api |
Alternative base URL (proxies, compatible gateways, self-hosted). |
DEFAULT_AI_EMBED_PROVIDER |
No |
— |
api |
Global embeddings provider. |
DEFAULT_AI_EMBED_API_KEY |
No |
— |
api |
API key of the embeddings provider. |
DEFAULT_AI_EMBED_MODEL |
No |
'' |
api |
Embeddings model. |
DEFAULT_AI_EMBED_BASE_URL |
No |
— |
api |
Base URL of the embeddings provider. |
9. Zoom (live classes)
Zoom's Server-to-Server credentials are not environment variables: they live encrypted per tenant (which is why TENANT_SETTINGS_ENC_KEY matters).
| Name |
Required |
Default |
Component |
Description |
ZOOM_WEBHOOK_SECRET |
Yes, to receive webhooks |
— |
api |
Zoom secret token used to verify the webhook's HMAC-SHA256 signature. Without it, events are rejected. |
ZOOM_REMINDER_CRON |
No |
*/5 * * * * |
worker |
Cron for the live class reminder worker. |
ZOOM_REMINDER_HOURS_BEFORE |
No |
2 |
worker |
How many hours ahead the reminder is sent. |
ZOOM_ATTENDANCE_SYNC_CRON |
No |
*/10 * * * * |
worker |
Cron for attendance reconciliation against the Zoom API. |
10. Payments — Stripe (the billing and subscriptions modules)
The canonical configuration lives per tenant under Administration → Settings → Payments (/admin/configuracion, the "Payments" tab): each academy stores its own secret key and webhook secret, encrypted. These variables are only the instance-wide global fallback — a tenant that has not configured its own lands here; if there is nothing here either, that tenant's checkout returns 503 until Stripe is configured somewhere (it never blocks the startup of mod.billing/mod.subscriptions, which are always registered).
| Name |
Required |
Default |
Component |
Description |
STRIPE_SECRET_KEY |
No — instance fallback |
— |
api |
Stripe secret key. A tenant with no credentials of its own in the panel lands here; one account per instance, shared by billing and subscriptions. |
STRIPE_WEBHOOK_SECRET |
No |
falls back to SUBSCRIPTIONS_WEBHOOK_SECRET |
api |
Secret of the billing webhook (…/modules/billing/webhook). |
BILLING_SUCCESS_URL_BASE |
No |
<AUTH_URL>/cursos |
api |
Base of the success URL for the one-off purchase checkout. |
BILLING_CANCEL_URL_BASE |
No |
<AUTH_URL>/cursos |
api |
Base of the cancel URL for the one-off checkout. |
SUBSCRIPTIONS_WEBHOOK_SECRET |
No |
falls back to STRIPE_WEBHOOK_SECRET |
api |
Secret of a dedicated webhook for subscriptions (keeping it separate is recommended to isolate auditing). |
SUBSCRIPTIONS_SUCCESS_URL_BASE |
No |
<AUTH_URL>/cuenta/suscripciones |
api |
Base of the success URL for the subscription checkout. |
SUBSCRIPTIONS_CANCEL_URL_BASE |
No |
<AUTH_URL>/cuenta/suscripciones |
api |
Base of the cancel URL for the subscription checkout. |
SUBSCRIPTIONS_GRACE_PERIOD_DAYS |
No |
3 |
api |
Days between the first failed charge and marking the subscription UNPAID and pausing the enrollment. |
SUBSCRIPTIONS_GRACE_EXPIRATION_CRON |
No |
0 * * * * |
worker |
Cron that expires subscriptions whose grace period has run out. |
SUBSCRIPTIONS_DAILY_CRON |
No |
0 9 * * * |
worker |
Cron for the daily summary and the advance renewal notices. |
SUBSCRIPTIONS_DAILY_TZ |
No |
UTC |
worker |
IANA time zone of the daily cron (Europe/Madrid…). |
SUBSCRIPTIONS_RENEWAL_WINDOW_DAYS |
No |
7 |
worker |
Window, in days, for the notice ahead of renewal/expiry. |
11. Member registration / Telegram
The canonical configuration lives per tenant under Administration → Settings → Registration (required verifiers, Telegram bot with an encrypted token, approver email). These variables are only the global fallback for single-tenant deployments; leave them empty in new installations.
| Name |
Required |
Default |
Component |
Description |
TELEGRAM_BOT_TOKEN |
No |
— |
api |
Bot token (global fallback). Requires TELEGRAM_GROUP_ID alongside it. If a tenant requires the Telegram verifier and there is no bot, its registration returns a fail-closed 503. |
TELEGRAM_GROUP_ID |
No |
— |
api |
Numeric group ID (prefixed with -100… in supergroups). |
TELEGRAM_BOT_USERNAME |
No |
— |
api, web |
Bot username without the @, needed for the Telegram Login Widget on the registration form. |
MEMBER_APPROVAL_EMAIL |
No |
— |
api |
Email of the approver who receives registration requests (global fallback; prefer the per-tenant setting). |
MEMBER_PURGE_CRON |
No |
0 3 * * * |
worker |
Cron for the GDPR purge of expired requests. |
MEMBER_RETENTION_DAYS |
No |
90 |
worker |
Retention days before request data is purged. |
12. Enterprise license and marketplace
| Name |
Required |
Default |
Component |
Description |
DIDACTA_LICENSE_KEY |
No |
— (Community mode) |
api, compose |
Enterprise license JWT signed by Didacta, read once at startup. Without it: License: community and EE capabilities disabled, unless a license was activated from Administration → License (the environment wins over the panel). If invalid: HTTP 402/401 on gated endpoints. Changing it through this route requires restarting the container; from the panel it reloads hot. |
DIDACTA_DEV_BYPASS |
No |
false |
api, compose |
License bypass: enables every capability. Development only — it is ignored with NODE_ENV=production and emits a visible WARN. |
MARKETPLACE_PUBLIC_KEYS_DIR |
No |
the embedded directory |
api |
Directory holding the public keys that verify the signature of marketplace module .zip packages. |
13. Telemetry, registration and observability
| Name |
Required |
Default |
Component |
Description |
DIDACTA_TELEMETRY_DISABLED |
No |
false |
api |
Disables the anonymous daily heartbeat. Accepts true/1/yes. See Telemetry. |
DIDACTA_TELEMETRY_URL |
No |
falls back to DIDACTA_REGISTRY_URL |
api |
Alternative heartbeat endpoint (tests, corporate proxies). Fixed 5 s timeout. |
DIDACTA_REGISTRY_URL |
No |
— (registration disabled) |
api |
Endpoint of the identified opt-in registration (a different level from the anonymous heartbeat). |
METRICS_TOKEN |
No |
— (/metrics open) |
api |
Optional bearer token for the Prometheus /metrics endpoint. If it is defined, it is required. |
AUDIT_REPORT_HMAC_KEY |
No |
embedded fallback key |
api |
HMAC-SHA256 master key signing exported audit reports (verifiable offline with tools/audit-report-verify.mjs). In production it must be overridden: the fallback is public. |
WEBHOOKS_TIMEOUT_MS |
No |
5000 |
api, worker |
Timeout of the POST to an outgoing webhook endpoint. |
WEBHOOKS_COMMUNITY_MAX_ENDPOINTS |
No |
1 |
api |
Maximum webhook endpoints per tenant on Community (Enterprise: 20). |
WEBHOOKS_COMMUNITY_MAX_EVENTS |
No |
3 |
api |
Maximum event types per endpoint on Community (Enterprise: unlimited). |
WEBHOOKS_ENTERPRISE_MAX_ENDPOINTS |
No |
20 |
api |
Maximum endpoints with the feat:api.webhooks.high_throughput capability. |
14. Development seed (BOOTSTRAP_*)
The real setup wizard (/setup) reads no environment variables at all: the first start is configured through the web interface. These variables belong exclusively to the programmatic development seed (pnpm db:seed).
| Name |
Required |
Default |
Component |
Description |
BOOTSTRAP_TENANT_SLUG |
No |
demo |
seed |
Slug of the seeded tenant. |
BOOTSTRAP_TENANT_NAME |
No |
Demo |
seed |
Display name of the tenant. |
BOOTSTRAP_EMAIL |
No |
admin@example.com |
seed |
Email of the initial admin. |
BOOTSTRAP_NAME |
No |
Admin |
seed |
Name of the initial admin. |
BOOTSTRAP_PASSWORD |
Yes, for the seed |
— |
seed |
Admin password. Deliberately without a default, so no known credentials are ever created. |
BOOTSTRAP_DOMAINS |
No |
localhost,127.0.0.1 |
seed |
CSV domains associated with the tenant (tenant resolution by host). |
15. Tests and E2E (contributors)
| Name |
Default |
Description |
TEST_DATABASE_URL |
— |
Database for the integration tests (the ephemeral Postgres from docker-compose.test.yml, port 5433). |
E2E_BASE_URL |
http://localhost:3010 |
Playwright's baseURL. |
E2E_API_URL |
http://localhost:3000 |
API base for the E2E HTTP helpers. |
E2E_ADMIN_EMAIL / E2E_ADMIN_PASSWORD |
— |
Credentials of the seeded admin the E2E suite signs in with. |
E2E_TENANT_SLUG |
demo |
Tenant the E2E suite runs against. |
E2E_AUTH_SECRET |
falls back to AUTH_SECRET |
Signs Telegram tickets in the registration E2E tests. |
E2E_TELEGRAM_BOT_TOKEN |
falls back to TELEGRAM_BOT_TOKEN |
Signs the Telegram Login Widget payload in E2E. |
E2E_STRIPE_WEBHOOK_SECRET / E2E_ZOOM_WEBHOOK_SECRET |
— |
Sign simulated webhooks in the payments/Zoom E2E tests. |
PROD_SMOKE |
— |
Switch for the smoke tests against production (only with the exact value 1). |
PROD_TEST_EMAIL / PROD_TEST_PASSWORD / PROD_TENANT_SLUG / PROD_COURSE_SLUG / PROD_EXPECTED_COURSE |
— |
Parameters of the production smoke test. |
16. Image build variables
Only relevant if you build your own image with docker build:
| Name |
Default |
Description |
DIDACTA_VERSION |
the repository version |
Dockerfile ARG; it materialises as DIDACTA_CORE_VERSION. |
SKIP_TYPE_CHECK |
0 |
With 1, the Next.js build skips typecheck and ESLint (types are validated in CI). |
NEXT_TELEMETRY_DISABLED |
1 |
Next.js's own telemetry, disabled in the official image. |
HUSKY |
0 |
Disables Git hooks inside the image. |