Configuration
Every environment variable Adcraft reads, with required or optional status and defaults, plus the settings you change in the admin panel instead.
7 min readUpdated Oct 17, 2026Applies to Adcraft 1.0.0
On this page
Adcraft is configured in two places:
- Environment variables hold everything about the server: the database, secrets, sign-in, storage and every provider key. They are read from
.envat the project root (in development and bynext start), or from the container's environment. Change them and restart. - The admin panel holds what an operator changes day to day without a restart: the maintenance banner, sign-ups, trial credits, plan feature switches, guardrail defaults, and the AI model catalogue with credit prices. See Admin-panel settings.
.env.example in the package lists the variables with comments. A blank value means that integration is off.
Core
| Variable | Required | Default | What it does |
|---|---|---|---|
AUTH_SECRET |
Yes | None | Signs session tokens. Also the source of the ad-token encryption key when TOKEN_ENCRYPTION_KEY is not set. Generate with openssl rand -base64 32. |
AUTH_URL |
Production | http://localhost:3000 in .env.example |
Your public HTTPS address, no trailing slash. Sign-in only trusts the request host in production when this (or AUTH_TRUST_HOST=true) is set. Magic links, invitations, share links, OAuth callbacks and API file links are built from it. |
DATABASE_URL |
Production | Embedded PGlite | PostgreSQL connection string. When it is set, the Docker container runs migrations on start. |
PGLITE_DATA_DIR |
No | .data/pglite in the project folder |
Where the embedded evaluation database keeps its files when DATABASE_URL is not set. In Docker, point it at the mounted volume (for example /data/pglite). |
NEXT_PUBLIC_APP_URL |
No | None | Your public address, used where AUTH_URL is not set: the site name on the privacy policy and the ad-platform OAuth callbacks. |
ADMIN_EMAILS |
For the first admin | None | Comma-separated platform admins. A listed address is an admin on every request and cannot be revoked in the panel; removing it demotes that user unless the admin flag was granted in Admin → Users. See First admin. |
DEV_LOGIN |
No | On in development | 0 hides the development sign-in box. It is never shown when NODE_ENV is production, whatever this says. |
Sign-in and email
| Variable | Default | What it does |
|---|---|---|
RESEND_API_KEY |
None | Turns on magic-link sign-in, and is used for invitations, "finished" emails and deletion requests. Without it, no email is sent. |
EMAIL_FROM |
Adcraft <onboarding@resend.dev> in code |
Sender for every email. The default is Resend's test sender, which is only for testing, so production must set it to an address on a domain you have verified in Resend. |
AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET |
None | "Sign in with Google". Shown when AUTH_GOOGLE_ID is set. Redirect URI: <AUTH_URL>/api/auth/callback/google. |
SUPPORT_EMAIL |
PRIVACY_EMAIL, then support@example.com |
Contact address shown on the suspended-workspace page. Set it to your own address. |
PRIVACY_EMAIL |
SUPPORT_EMAIL, then privacy@example.com |
Contact address on the privacy policy and Settings → Privacy, and where workspace deletion requests are emailed. Set it to your own address. |
In production, set RESEND_API_KEY or the Google pair, or nobody can sign in. The privacy policy reads PRIVACY_EMAIL and the site name from AUTH_URL (or NEXT_PUBLIC_APP_URL) on each request, so these take effect on restart without a rebuild.
AI providers
Every key is optional; each one switches on the models of that provider. AI models and providers explains what each powers.
| Variable | Powers |
|---|---|
ANTHROPIC_API_KEY |
Claude text models: concepts, copy, scripts, brief help. ANTHROPIC_AUTH_TOKEN is also accepted. |
FAL_KEY |
The default image models, all built-in video models and background removal |
OPENAI_API_KEY |
GPT Image 2.5 models and GPT text models |
XAI_API_KEY |
Grok Imagine Image 2.0 (keys start xai-) |
REPLICATE_API_TOKEN |
Replicate models (two examples ship disabled) |
RUNWAYML_API_SECRET |
Runway Gen-4 models (ship disabled) |
HEYGEN_API_KEY |
AI presenters, avatars, digital twins, looks, the presenter library, HeyGen voices, voice cloning and design |
ELEVENLABS_API_KEY |
Voice-over for presenter videos, and ElevenLabs voices in the voice library |
GEMINI_API_KEY, GROQ_API_KEY, TOGETHER_API_KEY, MISTRAL_API_KEY, DEEPSEEK_API_KEY, OPENROUTER_API_KEY |
Not used on their own. Name one of these as the key of an OpenAI-compatible text model you add in Admin → Models. |
Note
XAI_API_KEY is for xAI's Grok. GROQ_API_KEY is for the unrelated Groq inference service. They are easy to confuse.
File storage
| Variable | Default | What it does |
|---|---|---|
LOCAL_STORAGE_DIR |
.data/files in the project folder; /data/files in the Docker image |
Where uploads and generated media are written when R2 is not configured. Must be on persistent storage. |
R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET |
None | Store media in a Cloudflare R2 bucket instead. All four must be set. Create the bucket first, then an R2 API token with object read and write access. Admin → Providers shows the bucket name from R2_BUCKET. |
R2_PUBLIC_BASE |
None | Optional public or CDN address for the bucket, used for a few provider-facing links such as voice previews. Most files are still served through /api/files, which checks that the viewer belongs to the workspace. |
Storage supports Cloudflare R2 only; there is no setting for another S3-compatible endpoint.
Background jobs
| Variable | What it does |
|---|---|
INNGEST_EVENT_KEY |
Sends jobs to Inngest Cloud. Without it, jobs run inside the web process. |
INNGEST_SIGNING_KEY |
Lets Inngest call /api/inngest securely. Set it together with the event key. |
INNGEST_DEV |
Local only: use the Inngest Dev Server. Remove in production. |
See Background jobs for what changes with Inngest.
Backups
| Variable | Default | What it does |
|---|---|---|
BACKUP_RETENTION_DAYS |
14 |
How long nightly dumps are kept |
BACKUP_DIR |
.data/backups in the project folder |
Where dumps go when R2 is not configured. In Docker, use a path on the volume, such as /data/backups. |
R2_BACKUP_BUCKET |
R2_BUCKET |
A separate R2 bucket for dumps |
The nightly backup only runs when Inngest is configured. See Backups.
Billing
| Variable | What it does |
|---|---|
STRIPE_SECRET_KEY |
Turns on real payments. Without it, purchases are simulated in development; in production they are refused unless ALLOW_SIMULATED_BILLING is true. |
ALLOW_SIMULATED_BILLING |
true lets a production install without STRIPE_SECRET_KEY simulate purchases, granting plans and credits with no payment. Only for a demo site that should hand out free credits. Leave it unset otherwise. |
STRIPE_WEBHOOK_SECRET |
Signing secret of the /api/stripe/webhook endpoint |
STRIPE_PRICE_STARTER_MONTH, STRIPE_PRICE_STUDIO_MONTH, STRIPE_PRICE_AGENCY_MONTH |
Monthly price IDs for the three plans |
STRIPE_PRICE_STARTER_YEAR, STRIPE_PRICE_STUDIO_YEAR, STRIPE_PRICE_AGENCY_YEAR |
Read by the code, but the billing page only offers monthly plans in 1.0.0 |
STRIPE_PRICE_TOPUP |
One-time price for the credit top-up |
See Selling it as SaaS.
Ad platforms
Without these, each platform uses a built-in sandbox. See Publishing and performance.
| Variable | What it does |
|---|---|
META_APP_ID, META_APP_SECRET |
Meta (Facebook and Instagram) Marketing API |
META_PAGE_ID |
Default Facebook Page for Meta ads. Optional: a Page can also be chosen on each campaign. |
TIKTOK_APP_ID, TIKTOK_APP_SECRET |
TikTok Marketing API |
GOOGLE_ADS_CLIENT_ID, GOOGLE_ADS_CLIENT_SECRET, GOOGLE_ADS_DEVELOPER_TOKEN |
Google Ads API. All three are needed. |
GOOGLE_ADS_LOGIN_CUSTOMER_ID |
Optional manager (MCC) account ID |
TOKEN_ENCRYPTION_KEY |
Base64 of 32 random bytes. Encrypts ad-platform tokens. Defaults to a key derived from AUTH_SECRET. |
Observability
| Variable | What it does |
|---|---|
SENTRY_DSN |
Also send unhandled server errors to Sentry. They are always listed at Admin → Errors. |
NEXT_PUBLIC_APP_VERSION |
Version shown by /api/health and recorded with errors |
Rendering and advanced
Usually left blank.
| Variable | Default | What it does |
|---|---|---|
FFMPEG_PATH |
The binary from ffmpeg-static, then ffmpeg on the PATH |
Use your own FFmpeg build |
REMOTION_BROWSER_EXECUTABLE |
Remotion's Chrome Headless Shell | Use an installed Chrome or Chromium for video rendering and website screenshots |
ADCRAFT_REMOTION_BUNDLE_DIR |
A folder in the system temp directory | Where the video composition bundle is cached |
HEYGEN_API_BASE, HEYGEN_UPLOAD_BASE, ELEVENLABS_API_BASE, RUNWAY_API_BASE |
The providers' public API addresses | Override a provider's API address |
NEXT_PUBLIC_APP_URL |
None | Fallback for the OAuth callback address when AUTH_URL is not set |
PORT, HOSTNAME |
3000 and 0.0.0.0 in the Docker image |
Listening port and address |
Demo mode
| Variable | What it does |
|---|---|
DEMO_MODE |
true adds two one-click buttons to the sign-in page, Explore the ad studio and Explore the admin panel, and seeds a sample workspace and sample customers on first start (about 25 MB of files, no AI calls). Demo accounts use the reserved demo.invalid domain and are read-only: every change, generation, render, purchase, email and publish is refused on the server. Real accounts are unaffected. |
DEMO_ASSETS_DIR |
Optional. Where the seed reads its sample images and videos. Defaults to the files shipped in the image. |
Note
The demo admin sees only the demo world, never real workspaces, emails or money. Real admins see everything except the demo world, so sample customers do not inflate your numbers.
Admin-panel settings
These live in the database and are changed by a platform admin, with no restart:
| Where | What |
|---|---|
| Admin → Settings & flags | Maintenance banner, sign-ups on or off, trial credits, plan feature switches (product video, UGC, publishing), guardrail defaults (monthly provider cost cap, spend approval threshold, HeyGen voice slots, rate limit). See Platform settings. |
| Admin → Models & pricing | Which AI models are offered, the default per kind, their credit prices, and custom models. See Managing models. |
Workspace owners have their own settings under Settings → Guardrails: monthly credit limit, spend approval threshold, "finished" emails and approval before publishing.
Provider keys are not editable in the admin panel; Admin → Providers shows which ones are set.
A complete production example
# Core
DATABASE_URL=postgres://user:password@db-host:5432/adcraft
AUTH_SECRET=base64-32-bytes
AUTH_URL=https://ads.example.com
ADMIN_EMAILS=you@example.com
TOKEN_ENCRYPTION_KEY=base64-32-bytes
# Sign-in and email
RESEND_API_KEY=re_...
EMAIL_FROM=Your Studio <login@ads.example.com>
SUPPORT_EMAIL=support@example.com
PRIVACY_EMAIL=privacy@example.com
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
# AI
ANTHROPIC_API_KEY=sk-ant-...
FAL_KEY=...
HEYGEN_API_KEY=...
ELEVENLABS_API_KEY=...
# Jobs
INNGEST_EVENT_KEY=...
INNGEST_SIGNING_KEY=...
# Storage (or mount a volume at /data and skip these)
R2_ACCOUNT_ID=...
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_BUCKET=your-bucket
# Billing
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE_STARTER_MONTH=price_...
STRIPE_PRICE_STUDIO_MONTH=price_...
STRIPE_PRICE_AGENCY_MONTH=price_...
STRIPE_PRICE_TOPUP=price_...