Environment Variables#
All environment variables are configured in the root .env file.
bash cp .env.example .env
Backend Variables (Server Only)#
Basic#
Variable Description Example NODE_ENVRuntime environment development / production
Database#
Variable Description Example POSTGRES_CONNECTION_STRINGPostgreSQL connection string postgresql://admin:admin@localhost:5432/stackflare
JWT#
Variable Description Example JWT_SECRETJWT signing secret your-secret-keyJWT_EXPIRES_INToken expiration 365d
API Authentication#
Variable Description Example API_KEYSecret for machine-to-machine calls to protected endpoints, sent via the x-api-key header (e.g. external cron calling /v1/cron/free-packages) your_random_api_key
Email#
Switch the sending service via MAIL_PROVIDER (defaults to ses).
Variable Description Example MAIL_SEND_ENABLEDEnable email sending. When false, emails are not sent and the verification code is printed to the server console log (grab it from the logs during development) true / falseMAIL_PROVIDERProvider: ses (AWS SES) / cloudflare (Cloudflare Email) cloudflareMAIL_FROM_NAMESender name Your App NameMAIL_FROM_ADDRESSSender email no-reply@example.com
MAIL_PROVIDER=cloudflare: requires CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN below.
MAIL_PROVIDER=ses: requires the AWS credentials below (AWS_REGION / AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY).
Cloudflare (shared by Email / R2)#
Variable Description CLOUDFLARE_ACCOUNT_IDCloudflare account ID (needed for both Cloudflare email sending and R2 storage) CLOUDFLARE_API_TOKENCloudflare API token (used for sending when MAIL_PROVIDER=cloudflare)
AWS (SES email / S3 storage)#
Variable Description Example AWS_REGIONAWS region us-east-1AWS_ACCESS_KEY_IDAWS access key (can be left empty on EC2/ECS with an IAM Role) — AWS_SECRET_ACCESS_KEYAWS secret key — S3_BUCKET_NAMES3 bucket name (when using S3 storage) your_s3_bucket
Cloudflare R2 Storage#
Variable Description R2_ACCESS_KEY_IDR2 access key R2_SECRET_ACCESS_KEYR2 secret key R2_BUCKET_NAMEBucket name
Object storage supports R2 and S3 at the same time : setting R2_ACCESS_KEY_ID enables R2, setting S3_BUCKET_NAME enables S3. When no provider is specified, R2 is used by default (e.g. invoice/receipt PDFs are auto-uploaded to R2); code can also pass a provider to pick R2 or S3 per upload.
R2 Bucket CORS Configuration (Required)#
Browser-to-R2 direct uploads (presigned PUT and multipart) require CORS to be configured on the R2 bucket — otherwise the browser blocks the request, or multipart fails because ETag headers can't be read.
Go to Cloudflare Dashboard → R2 → your bucket → Settings → CORS Policy and add:
json [
{
"AllowedOrigins" : [ "http://localhost:3000" , "https://yourdomain.com" ] ,
"AllowedMethods" : [ "GET" , "PUT" , "HEAD" ] ,
"AllowedHeaders" : [ "*" ] ,
"ExposeHeaders" : [ "*" ]
}
]
Notes:
AllowedOrigins: list every origin that will upload (dev + production)
AllowedMethods must list methods explicitly (S3/R2 CORS does not accept * wildcard ). PUT for upload; GET/HEAD for fetch / <img crossOrigin> preflight
ExposeHeaders: ["*"] is simplest, otherwise must include "ETag" or multipart complete will fail because the client can't read part ETags
Stripe#
Variable Description STRIPE_SECRET_KEYStripe API key STRIPE_WEBHOOK_SECRET_KEYWebhook signing secret
Cloudflare Turnstile#
Variable Description TURNSTILE_VERIFY_URLVerification endpoint TURNSTILE_SECRET_KEYServer-side secret
Frontend Variables (PUBLIC_ prefix)#
Exposed to the browser. Do not put sensitive data here.
Variable Description Example PUBLIC_APP_URLApp URL http://localhost:3000PUBLIC_TITLEApp name My SaaSPUBLIC_GOOGLE_CLIENT_IDGoogle OAuth Client ID 446xxx.apps.googleusercontent.comPUBLIC_TURNSTILETurnstile site key 0x4AAAxxxPUBLIC_DEFAULT_LANGDefault language enPUBLIC_CLARITY_PROJECT_IDMicrosoft Clarity project ID, leave empty to disable abc123PUBLIC_GOOGLE_ANALYTICS_IDGoogle Analytics ID, leave empty to disable G-XXXXXXXXXX