Skip to content
flexcal Documentation

Configuration

Configuration is entirely environment-driven. .env.example in the repository root is the authoritative list; the tables below cover the variables that matter most for a self-hosted instance.

Run-time variables

These must be present when the app starts.

VariableDescriptionRequiredDefault
DATABASE_URLDatabase URL with credentials. If you use a connection pooler, point this at the pooler.requiredpostgresql://unicorn_user:magical_password@database:5432/calendso
NEXT_PUBLIC_WEBAPP_URLBase URL of the site. The image ships a placeholder in its statically built files, which is rewritten to this value the first time the container starts.optionalhttp://localhost:3000
NEXTAUTH_URLLocation of the auth server. Defaults to the flexcal instance itself.optional{NEXT_PUBLIC_WEBAPP_URL}/api/auth
NEXTAUTH_SECRETCookie encryption key. Must match the build-time value. Generate with openssl rand -base64 32.requiredsecret
CALENDSO_ENCRYPTION_KEYAuthentication encryption key, 32 bytes for AES256. Must match the build-time value. Generate with openssl rand -base64 24.requiredsecret
SKIP_DB_MIGRATIONSSet to 1 to stop the container applying migrations on start. Leave unset for Docker Compose, which has nowhere else to run them. Set it when the deployment migrates once per release, otherwise every replica races the others.optionalunset
SKIP_APP_STORE_SEEDSet to 1 to stop the container seeding the app store on start. Same reasoning as SKIP_DB_MIGRATIONS; the seed costs roughly 8s of every pod’s startup.optionalunset
NEXT_PUBLIC_VAPID_PUBLIC_KEYWeb push public key, generated with npx web-push generate-vapid-keys.required for pushunset
VAPID_PRIVATE_KEYWeb push private key from the same key pair.required for pushunset
DATABASE_SCHEMASchema that Prisma resolves unqualified objects against. Appended to DATABASE_URL and DATABASE_DIRECT_URL as schema= when neither already names one, so an explicit schema= in the URL always wins. Only change this if the deployment genuinely keeps flexcal’s tables outside public.optionalpublic

A note on the database schema

Prisma only issues SET search_path when the connection URL carries a schema= argument. Without one, the session keeps the PostgreSQL default of "$user", public, so on a deployment where the database role owns a schema of the same name, unqualified CREATE TABLE / CREATE TYPE in a migration lands in that role schema rather than in public. Prisma then looks in public, finds nothing, and the application keeps working only by search_path accident: a connection using a different role or search_path breaks.

Setups where the role owns a same-named schema include Crunchy PostgreSQL Operator with autoCreateUserSchema, Supabase, and any database where someone created a schema named after the login role.

The container handles this for you: scripts/start.sh pins the schema before touching the database.

:::caution A deployment that runs prisma migrate deploy itself rather than through the container entrypoint (the Helm chart does, in a pre-upgrade Job) should either source scripts/db-url.sh and call flexcal_pin_database_urls first, or put ?schema=public in the URLs directly. :::

Databases that already have stranded objects are repaired by the 20260818120000_relocate_shadow_schema_objects migration, which moves them back into public. It reports a warning and changes nothing where public already holds an object of the same name.

Build-time variables

These are baked in when the image or the app is built. Changing them means rebuilding.

VariableDescriptionRequiredDefault
DATABASE_URLOnly needs to be parseable at build time; no connection is made.requiredpostgresql://unicorn_user:magical_password@database:5432/calendso
MAX_OLD_SPACE_SIZENode.js heap size for the build, in MB.optional6144
NEXTAUTH_SECRETCookie encryption key.requiredsecret
CALENDSO_ENCRYPTION_KEYAuthentication encryption key.requiredsecret
NEXT_PUBLIC_WEBAPP_URLDefault base URL for the built image; a deployment overrides it with the run-time variable of the same name.optionalhttp://localhost:3000
NEXT_PUBLIC_WEBSITE_TERMS_URLCustom URL for the terms and conditions page.optional
NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URLCustom URL for the privacy policy page.optional
NEXT_PUBLIC_CALCOM_VERSIONVersion string rendered in the footer; unset renders dev.optional
CSP_POLICYContent Security Policy mode, see below.optional
CALCOM_TELEMETRY_DISABLEDSet to 1 to disable anonymous usage telemetry.optional

Content Security Policy

Set CSP_POLICY="non-strict" to enable Strict CSP with the exception of unsafe-inline in style-src. Custom changes to an instance may need adjusting to stay CSP-compatible.

Strict CSP is currently enforced only on the login page. Other server-rendered pages run it in report-only mode to surface problems. Statically generated pages are not covered yet.

Logging

NEXT_PUBLIC_LOGGER_LEVEL controls verbosity for all tRPC queries and mutations. The level you set is the minimum that gets logged:

ValueLevel
0silly
1trace
2debug
3info
4warn
5error
6fatal
Terminal window
echo 'NEXT_PUBLIC_LOGGER_LEVEL=3' >> .env

App credentials

Third-party integrations read their credentials from .env and .env.appStore. See the Apps section for the per-provider setup.