Skip to content

Environment Variables

Contentrain Studio is configured entirely through environment variables. Copy .env.example to .env and fill in the values for your deployment.

Core Application

VariableRequiredDefaultDescription
NUXT_SESSION_SECRETYes--AES-256 cookie encryption key. Minimum 32 characters.
NUXT_SESSION_SECRET_PREVIOUSNo--Previous secret for key rotation. Set during migration window, remove after.
NUXT_PUBLIC_SITE_URLYeshttp://localhost:3000Public-facing application URL. Used for OAuth callbacks and email links.
NUXT_PUBLIC_GITHUB_APP_SLUGNocontentrain-studioGitHub App slug for installation redirect URL.
NUXT_PUBLIC_TEMPLATE_OWNERNoContentrainGitHub org that owns starter kit template repos.
NUXT_PUBLIC_BILLING_ENABLEDNofalseBilling UI visibility. Auto-derived on boot from configured payment plugins (true when Polar or Stripe is set). Set explicitly only to override.
NODE_ENVNodevelopmentSet to production for production deployments.

Session Secret

Generate a secure session secret:

bash
openssl rand -base64 32

Deployment Profile

Studio auto-detects its deployment profile at boot from whether the Enterprise bridge (ee/) loads and whether a payment plugin is configured. Set these only to pin behaviour explicitly.

VariableRequiredDefaultDescription
NUXT_DEPLOYMENT_PROFILENo-- (auto-detect)managed | dedicated | on-premise | community. Server-side profile override.
NUXT_PUBLIC_DEPLOYMENT_PROFILENo--Client-visible profile. managed | dedicated | on-premise | community.
NUXT_PUBLIC_DEPLOYMENT_EDITIONNo--Client-visible edition. ee | agpl.
NUXT_PUBLIC_DEPLOYMENT_BILLING_MODENo--Client-visible billing mode. polar | stripe | flat | off.

Production Builds

Production (Nitro compiled output) freezes runtimeConfig.public, so the auto-derive plugin cannot mutate the snapshot. Set the three NUXT_PUBLIC_DEPLOYMENT_* variables explicitly in production to mirror the server-side resolveDeployment() result on the client. Dev mode does not need them.

Provider Selection

Studio's auth and database providers ship as matched pairs, selected at boot. Two pairs are supported: supabase + supabase (the default) and managed + postgres (Supabase-free, plain PostgreSQL 14+). Mixed pairs (e.g. supabase auth with postgres database) are rejected at boot.

VariableRequiredDefaultDescription
NUXT_AUTH_PROVIDERNosupabaseAuth implementation: supabase | managed.
NUXT_DATABASE_PROVIDERNosupabaseDatabase implementation: supabase | postgres.

Valid pairs

Only supabase+supabase and managed+postgres are accepted. Setting one without the other, or crossing them, fails boot validation with an explicit error.

Supabase (Auth + Database)

Required only for the Supabase pair (NUXT_DATABASE_PROVIDER=supabase, the default). Leave these unset when running the managed + postgres pair.

VariableRequiredDefaultDescription
NUXT_SUPABASE_URLRequired (Supabase pair)--Supabase project URL (e.g., https://your-project.supabase.co).
NUXT_SUPABASE_SERVICE_ROLE_KEYRequired (Supabase pair)--Service role key with admin database access. Keep private. Must carry the service_role JWT claim -- boot rejects an anon key pasted here.
NUXT_SUPABASE_ANON_KEYRequired (Supabase pair)--Anonymous key for client-side auth operations.

Supabase OAuth (for local Supabase CLI)

These are only needed when running Supabase locally via the CLI:

VariableRequiredDefaultDescription
SUPABASE_AUTH_EXTERNAL_GITHUB_CLIENT_IDNo--GitHub OAuth client ID for Supabase auth.
SUPABASE_AUTH_EXTERNAL_GITHUB_SECRETNo--GitHub OAuth client secret for Supabase auth.
SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_IDNo--Google OAuth client ID for Supabase auth.
SUPABASE_AUTH_EXTERNAL_GOOGLE_SECRETNo--Google OAuth client secret for Supabase auth.

Managed + Postgres Pair

Required only when running the Supabase-free pair (NUXT_AUTH_PROVIDER=managed, NUXT_DATABASE_PROVIDER=postgres). The managed auth provider signs its own JWTs, runs the GitHub/Google OAuth dance directly, and sends magic-link/invite emails through Resend. Leave all of these unset on the Supabase pair.

VariableRequiredDefaultDescription
NUXT_POSTGRES_URLRequired (managed pair)--PostgreSQL 14+ connection string (e.g., postgres://user:pass@host:5432/contentrain). Required when NUXT_DATABASE_PROVIDER=postgres.
NUXT_AUTH_JWT_SECRETRequired (managed pair)--Minimum 32 characters. Signs the managed provider's access/refresh JWTs. Required when NUXT_AUTH_PROVIDER=managed.
NUXT_SESSION_PASSWORDRecommended (managed pair)--Minimum 32 characters. Session store for the nuxt-auth-utils OAuth module (separate from NUXT_SESSION_SECRET; stores no durable state). Dev auto-generates it; deployed builds must set it or every SSR load of /api/_auth/session 500s (boot warns, does not fail).
NUXT_OAUTH_GITHUB_CLIENT_IDRequired (managed pair)--GitHub OAuth App client ID for login. Callback: {NUXT_PUBLIC_SITE_URL}/api/auth/oauth/github.
NUXT_OAUTH_GITHUB_CLIENT_SECRETRequired (managed pair)--GitHub OAuth App client secret.
NUXT_OAUTH_GOOGLE_CLIENT_IDNo--Google OAuth client ID for login. Google sign-in is disabled (button hidden) when unset.
NUXT_OAUTH_GOOGLE_CLIENT_SECRETNo--Google OAuth client secret.
NUXT_REVIEW_ACCOUNT_EMAILNo--Directory-review password-login account (managed pair only). The only address the review login accepts. Must be set together with the password.
NUXT_REVIEW_ACCOUNT_PASSWORDNo--Password for the review-login account. Minimum 16 characters (it gates a real password login). Unset means /auth/review-login does not exist.
NUXT_OPENAI_APPS_CHALLENGENo--Domain-verification token served at /.well-known/openai-apps-challenge (managed pair, remote MCP surface).

Resend is required on the managed pair

NUXT_RESEND_API_KEY (see Email) is required when NUXT_AUTH_PROVIDER=managed -- it delivers magic-link and invite emails. On the Supabase pair it stays optional.

GitHub App

VariableRequiredDefaultDescription
NUXT_GITHUB_APP_IDYes--GitHub App ID (numeric).
NUXT_GITHUB_CLIENT_IDYes--GitHub App client ID.
NUXT_GITHUB_CLIENT_SECRETYes--GitHub App client secret.
NUXT_GITHUB_PRIVATE_KEYYes--Base64-encoded .pem private key file.
NUXT_GITHUB_WEBHOOK_SECRETRecommended--HMAC-SHA256 secret for webhook payload verification. Validated only when NUXT_GITHUB_APP_ID is set; if missing, boot warns and webhook signature verification is disabled (it does not fail boot).

Encoding the Private Key

bash
base64 -i your-app.private-key.pem | tr -d '\n'

AI (Anthropic)

VariableRequiredDefaultDescription
NUXT_ANTHROPIC_API_KEYNo--Operator-managed Anthropic API key for the Studio instance. If omitted, users need BYOA (Bring Your Own API key).

CDN / Object Storage (Cloudflare R2)

VariableRequiredDefaultDescription
NUXT_CDN_R2_ACCOUNT_IDNo--Cloudflare account ID. Required for CDN and media features.
NUXT_CDN_R2_ACCESS_KEY_IDNo--R2 access key ID.
NUXT_CDN_R2_SECRET_ACCESS_KEYNo--R2 secret access key.
NUXT_CDN_R2_BUCKETNocontentrain-cdnR2 bucket name.

INFO

CDN and media library features require all four R2 variables to be set. If any are missing, useCDNProvider() and useMediaProvider() return null and those features are gracefully disabled.

Email (Resend)

VariableRequiredDefaultDescription
NUXT_RESEND_API_KEYNo--Resend API key for application emails (invites, notifications).
RESEND_API_KEYNo--Same key, read by local Supabase CLI for auth SMTP.
NUXT_EMAIL_SENDER_ADDRESSNo--Sender email address (e.g., [email protected]).
NUXT_EMAIL_SENDER_NAMENo--Sender display name (e.g., Contentrain Studio).

Billing

Studio supports two payment plugins. Polar is the default provider; Stripe is supported as a secondary, legacy plugin. When both are configured, Polar takes precedence (the plugin registry preference order is polar -> stripe).

Polar (default)

VariableRequiredDefaultDescription
NUXT_POLAR_ACCESS_TOKENNo--Polar organization access token (polar_oat_...). Activates the Polar plugin when set.
NUXT_POLAR_WEBHOOK_SECRETNo--Polar webhook signing secret (Standard Webhooks).
NUXT_POLAR_STARTER_PRODUCT_IDNo--Polar product ID for the Starter plan.
NUXT_POLAR_PRO_PRODUCT_IDNo--Polar product ID for the Pro plan.
NUXT_POLAR_SERVERNoproductionPolar environment: sandbox for testing, production for live.

Stripe (legacy / optional)

VariableRequiredDefaultDescription
NUXT_STRIPE_SECRET_KEYNo--Stripe secret key. Activates the Stripe plugin when set.
NUXT_STRIPE_WEBHOOK_SECRETNo--Stripe webhook signing secret for event verification.
NUXT_STRIPE_STARTER_PRICE_IDNo--Stripe Price ID for the Starter plan.
NUXT_STRIPE_PRO_PRICE_IDNo--Stripe Price ID for the Pro plan.

Self-Hosted Bypass

When no payment plugin (Polar or Stripe) is configured, Studio resolves to the on-premise profile (ee/ loaded) or community profile (ee/ missing) and hides the subscription UI. Core features work normally; premium features (CDN preview branches, custom variants, spam filter) remain gated by hasFeature().

Redis

VariableRequiredDefaultDescription
REDIS_URLNo--Redis connection URL (e.g., redis://localhost:6379). Strongly recommended for multi-instance production rate limiting; dev falls back to in-memory.
REDIS_CA_CERTNo--Custom CA certificate for TLS Redis connections (rediss://).

Sentry (Error & Performance Monitoring)

Optional. Leave NUXT_PUBLIC_SENTRY_DSN empty to disable Sentry entirely (the SDK no-ops on both client and server, and no telemetry leaves your infrastructure) -- this is the intended Community / self-host default.

VariableRequiredDefaultDescription
NUXT_PUBLIC_SENTRY_DSNNo--Your Sentry project DSN. Empty disables Sentry completely.
NUXT_PUBLIC_SENTRY_ENVIRONMENTNo--Environment tag: development | staging | production.
NUXT_PUBLIC_SENTRY_TRACES_SAMPLE_RATENo0.1Performance-tracing sample rate. Errors are always captured at 100%.
NUXT_PUBLIC_SENTRY_RELEASENo--Optional build/release identifier.

These three are build-time only, for source map upload during nuxt build. When all three are set, readable stack traces are uploaded. SENTRY_AUTH_TOKEN is a secret -- never expose it to forked CI or the client bundle.

VariableRequiredDefaultDescription
SENTRY_ORGNo--Sentry org slug (source map upload).
SENTRY_PROJECTNo--Sentry project slug (source map upload).
SENTRY_AUTH_TOKENNo--Sentry auth token. Enables source map upload when present.

Variable Resolution

Nuxt resolves runtime config variables using the NUXT_ prefix convention:

ts
// nuxt.config.ts
runtimeConfig: {
  sessionSecret: '',          // -> NUXT_SESSION_SECRET
  github: {
    appId: '',                // -> NUXT_GITHUB_APP_ID
    clientId: '',             // -> NUXT_GITHUB_CLIENT_ID
    privateKey: '',           // -> NUXT_GITHUB_PRIVATE_KEY
  },
  polar: {
    accessToken: '',          // -> NUXT_POLAR_ACCESS_TOKEN
    server: 'production',     // -> NUXT_POLAR_SERVER
  },
  public: {
    siteUrl: 'http://localhost:3000',  // -> NUXT_PUBLIC_SITE_URL
  },
}

Access in server code:

ts
const config = useRuntimeConfig()
console.log(config.github.appId)       // Server-only
console.log(config.public.siteUrl)     // Both server and client

Example .env File

bash
# Core
NUXT_SESSION_SECRET=your-random-32-character-string
NUXT_PUBLIC_SITE_URL=https://studio.yourdomain.com

# Provider pair — Supabase (default). Omit NUXT_AUTH_PROVIDER /
# NUXT_DATABASE_PROVIDER to use it.
NUXT_SUPABASE_URL=https://your-project.supabase.co
NUXT_SUPABASE_SERVICE_ROLE_KEY=eyJ...
NUXT_SUPABASE_ANON_KEY=eyJ...

# Provider pair — managed + postgres (Supabase-free). Use INSTEAD of the
# Supabase block above:
# NUXT_AUTH_PROVIDER=managed
# NUXT_DATABASE_PROVIDER=postgres
# NUXT_POSTGRES_URL=postgres://user:pass@host:5432/contentrain
# NUXT_AUTH_JWT_SECRET=your-random-32-character-string
# NUXT_SESSION_PASSWORD=your-random-32-character-string
# NUXT_OAUTH_GITHUB_CLIENT_ID=your-github-oauth-app-client-id
# NUXT_OAUTH_GITHUB_CLIENT_SECRET=your-github-oauth-app-client-secret
# NUXT_RESEND_API_KEY=re_abc123   # required on the managed pair

# GitHub App
NUXT_GITHUB_APP_ID=123456
NUXT_GITHUB_CLIENT_ID=Iv1.abc123
NUXT_GITHUB_CLIENT_SECRET=abc123def456
NUXT_GITHUB_PRIVATE_KEY=LS0tLS1CRUdJTi...
NUXT_GITHUB_WEBHOOK_SECRET=whsec_abc123

# AI (optional)
NUXT_ANTHROPIC_API_KEY=sk-ant-...

# Email (optional)
NUXT_RESEND_API_KEY=re_abc123
NUXT_EMAIL_SENDER_ADDRESS=[email protected]
NUXT_EMAIL_SENDER_NAME=Contentrain Studio

# Billing — Polar (default; optional)
NUXT_POLAR_ACCESS_TOKEN=polar_oat_...
NUXT_POLAR_WEBHOOK_SECRET=your-polar-webhook-secret
NUXT_POLAR_STARTER_PRODUCT_ID=uuid-of-starter-product
NUXT_POLAR_PRO_PRODUCT_ID=uuid-of-pro-product
NUXT_POLAR_SERVER=production

Released under the AGPL-3.0 License.