Environment variables

This page describes environment and deployment-related configuration for the monorepo.

Next.js app (site-nextjs) — official full stack

The production implementation in this monorepo today is primarily the Next.js app under site-nextjs/, with Convex, Better Auth, Square, and Radar. Most variables and file layout below are Next.js–specific (NEXT_*, App Router, Vercel).

Local development

For local development, we use .env and .env.local files.

Variable file overview

  • .env: Contains non-sensitive development defaults. Shared across some tools but overridden by .env.local in Next.js.

  • .env.local: Contains your personal API keys and secrets. This file is ignored by git.

  • .env.example: A template for the .env file.

  • .env.local.example: A template for the .env.local file.

Next.js encourages use of .env.local to store all personal secrets. While .env will work, it is less accurate for local overrides. Variables in .env.local override variables in .env, which is useful if you are testing a function locally and you don’t want to replace shared information in .env.

Because most software developers are unaware of the difference, they might drop sensitive information into .env instead of .env.local. To be safe, both are excluded from git via .gitignore. Other non-local versions (like .env.development) are also typically ignored to prevent hardcoded secrets in project history.

CI/CD pipeline

If you are trying to deploy this code via CI/CD pipelines on GitHub, Vercel, or other deployment platforms, do not use .env files to store variables. Environment variables for staging or production environments should be managed by secret managers or injected directly into the deployment pipeline.

Setup

To get started, copy the template files in the site-nextjs directory:

cd site-nextjs
cp .env.example .env
cp .env.local.example .env.local

Variable reference

Variable Description Source

FOOD_TRUCK_API_URL

Base URL for the API (server-side calls)

Internal / Zuplo

NEXT_PUBLIC_API_URL

Base URL for API calls from the frontend

Internal / Vercel Domain

NEXT_PUBLIC_MAP_PROVIDER

Tile provider for Find map. OpenFreeMap via MapLibre (openfreemap). Mapbox deferred.

Internal (Default: openfreemap)

NEXT_PUBLIC_RADAR_PUBLISHABLE_KEY

Publishable key for Radar geocoding / autocomplete only (not required for map tiles)

Radar Dashboard

CONVEX_DEPLOYMENT

Optional Convex CLI target (dev:… / prod:…). Leave unset locally while sharing production data so npx convex dev cannot push functions.

Convex Dashboard

NEXT_PUBLIC_CONVEX_URL

Convex HTTP URL the Next.js app queries. Until release, local + Vercel Preview/Development use the same production URL as test.foodtrucknerdz.com.

Convex Dashboard

CONVEX_DEPLOY_KEY

Deploy key so Vercel production builds can convex deploy (Convex deploy-key format, starts with prod:). Do not set on Preview, Development, or local .env.local while sharing prod data. Team copy: Bitwarden dashboard.convex.dev field ftn/ftn-site Prod API key (then set it as the Pulumi stack secret convex:deployKeyProd in the ftn-prod stack).

FTN_CONVEX_SCHEMA_REF_URL

Optional. Reference Convex URL for pnpm convex:schema-parity / /dev/schema-parity. Falls back to NEXT_PUBLIC_CONVEX_URL.

Convex Dashboard

FTN_CONVEX_SCHEMA_REF_KEY

Optional. Deploy/admin key for the reference deployment in schema parity. Falls back to CONVEX_DEPLOY_KEY. Local/tooling only — never commit.

Convex Dashboard

FTN_CONVEX_SCHEMA_DEV_URL

Optional. Personal/dev Convex URL for schema parity. Falls back to NEXT_PUBLIC_CONVEX_URL.

Convex Dashboard

FTN_CONVEX_SCHEMA_DEV_KEY

Optional. Deploy/admin key for the personal/dev deployment in schema parity. Falls back to CONVEX_DEPLOY_KEY. Local/tooling only — never commit.

Convex Dashboard

SQUARE_APPLICATION_ID

Square Application ID

Square Developer Portal

SQUARE_ACCESS_TOKEN

Square Access Token (Sandbox/Production)

Square Developer Portal

SQUARE_WEBHOOK_SIGNATURE_KEY

Square Webhook Signature Key

Square Developer Portal

NEXTAUTH_SECRET

Random string for NextAuth.js encryption

Generate with openssl rand -base64 32

ENCRYPTION_KEY

32-character key for data encryption (Local)

Any random 32-character string

TOKEN_ENCRYPTION_KEY

32-character key for sensitive token encryption (Vercel)

Any random 32-character string

BETTER_AUTH_SECRET

Secret for Better Auth session signing (use a long random string in production)

Generate with openssl rand -base64 32

BETTER_AUTH_URL

Public origin of the Next.js app as seen by the auth server (no trailing path). Better Auth stores sessions in SQLite: site-nextjs/data/auth.db locally, /tmp/ftn-auth.db on Vercel (ephemeral per instance).

e.g. http://localhost:3000 or your Vercel URL

NEXT_PUBLIC_APP_URL

Same origin as BETTER_AUTH_URL for the browser auth client; also used as Next.js metadataBase for canonical URLs, sitemap.xml, and Open Graph / Twitter image URLs

Must match deployment URL (include https:// in production)

NEXT_PUBLIC_GOOGLE_PLAY_URL / NEXT_PUBLIC_APP_STORE_URL / NEXT_PUBLIC_MICROSOFT_STORE_URL

Optional store listing URLs for homepage badges. Empty → Coming soon (do not invent links).

Play Console / App Store Connect / Partner Center when listings exist

NEXT_PUBLIC_GITHUB_RELEASE_OWNER / NEXT_PUBLIC_GITHUB_RELEASE_REPO

Optional. GitHub repo whose latest release assets feed the homepage Download button. Defaults to FoodTruckNerdz / ftn-app.

GitHub

FTN_DEVELOPER_EMAILS

Comma-separated list of sign-in emails granted the Convex platformRole of developer (FTN developer panel, /dev/ routes). Server-only; not exposed to the browser. Local next dev shows /dev/ without this list; production still requires the role and shows a denied page instead of redirecting home.

e.g. you@example.com,teammate@example.com

FTN_PR_EMAILS

Comma-separated list of sign-in emails granted platformRole of pr (approve/reject FTN-affiliated meetup host requests). If an email is also in FTN_DEVELOPER_EMAILS, developer wins.

e.g. pr@foodtrucknerdz.com

FTN_PR_NOTIFY_EMAIL

Inbox that receives “new host request” notifications. Defaults to support@foodtrucknerdz.com if unset.

e.g. pr@foodtrucknerdz.com

RESEND_API_KEY / FTN_TRANSACTIONAL_FROM

Optional. When set, host-request and approval emails send via Resend. Without the key, emails are logged server-side only. Transactional / app only — use sending host updates.foodtrucknerdz.com (e.g. support@updates.foodtrucknerdz.com) after domain verification. Marketing / journeys use Customer.io. Human Gmail send-as uses ZeptoMail (ops), not Resend. See Messaging & marketing.

Resend dashboard; DNS in org infra

Customer.io / Twilio (planned)

Fan sends (including owner-paid follower campaigns) are not wired yet. Customer.io is the marketing + multi-channel orchestration platform (US data center; Email, SMS, Push, In-app). Owner requests use existing Resend transactional mail to PR. Twilio is the planned SMS transport. Add site/API and Twilio secrets here when provisioned; never ship write keys to browsers. See Messaging & marketing (Customer.io) and Follower marketing.

Customer.io / Twilio

YOTI_CLIENT_SDK_ID / YOTI_PEM_PRIVATE_KEY

Optional. Yoti Age Verification credentials for affiliated host age + liveness checks. Leave unset in local/dev to use the stub verification path documented in Community events.

Yoti Age Verification docs

ADAPTY_PUBLIC_SDK_KEY

Adapty public SDK key for mobile (ftn-app via --dart-define=ADAPTY_PUBLIC_SDK_KEY=…) and Adapty Web API paywalls. Not a substitute for Better Auth. Create the app and access level premium in the Adapty dashboard. See Subscription management (Adapty).

Adapty Dashboard

ADAPTY_SECRET_API_KEY

Adapty secret API key for Next.js server-side profile and access-level checks (/api/adapty/access, Stripe sync). Never expose to browsers or mobile builds.

Adapty Dashboard → App Settings → API keys

GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET

Google OAuth credentials for Better Auth social sign-in

Google Cloud Console

GEMINI_API_KEY

Convex deployment only (not Next.js). Google AI Studio / Gemini API key for menu photo parsing (menuParseAction) and listing image auto-review (listingMediaReviewAction). Enable the Generative Language API in Google Cloud, create an API key, set it on the Convex dashboard for the FTN deployment. Without it, menu scan submissions fail at parse time; listing uploads stay pending/held for manual PR.

Google AI Studio or Cloud Console → APIs & Services → Credentials

GEMINI_MENU_MODEL

Optional. Convex-only model id for menu vision parse (default gemini-2.0-flash).

e.g. gemini-2.0-flash

GEMINI_LISTING_MEDIA_MODEL

Optional. Convex-only model id for listing logo/cover/gallery auto-review (falls back to GEMINI_MENU_MODEL, then gemini-2.0-flash).

e.g. gemini-2.0-flash

FACEBOOK_CLIENT_ID / FACEBOOK_CLIENT_SECRET

Meta (Facebook) OAuth credentials for Better Auth social sign-in. In the Meta app, add a Valid OAuth Redirect URI that matches your deployment: the app origin (same as BETTER_AUTH_URL) plus path /api/auth/callback/facebook.

Meta for Developers

FACEBOOK_CONFIG_ID

Vercel deployment

For production deployments on Vercel, variables are managed in the Vercel Dashboard under Settings > Environment Variables.

Important notes

  1. CONVEX_DEPLOY_KEY is required on Vercel Production only. Preview and Development skip convex deploy and must set NEXT_PUBLIC_CONVEX_URL to the production Convex URL (shared data until release).

  2. NEXT_PUBLIC_CONVEX_URL is set explicitly for Preview/Development. Production builds still let pnpm convex deploy --cmd inject it; keeping the same URL in the dashboard is fine.

  3. Square variables are only needed if you’re using Square POS integration. Get credentials from the Square Developer Portal.

  4. Radar variables are needed for place search / geocoding (typeahead, reverse geocode). Find map tiles use MapLibre + OpenFreeMap and do not require a Radar key.

  5. Map tiles: MapLibre GL JS loads OpenFreeMap styles directly. Mapbox is deferred. Radar is not used for the map shell.

  6. TOKEN_ENCRYPTION_KEY should be a strong random string (at least 32 characters). Use it to encrypt sensitive data like Square access tokens.

  7. NEXT_PUBLIC_* variables are exposed to the browser. Never put secrets in these variables.

  8. Do not pull environment variables via Vercel CLI. If prompted by vercel --prod to download variables, select NO. This prevents Vercel from overwriting your local setup or creating redundant .env files.

  9. Social login: Set BETTER_AUTH_URL and NEXT_PUBLIC_APP_URL to the production site origin. For Facebook, register the matching /api/auth/callback/facebook redirect URI in the Meta app.

  10. Square: Use one Square application for both POS linking and seller sign-in. Register two redirect URIs in the Square app: the POS link URL (SQUARE_REDIRECT_URI, path /api/auth/callback/square) and the Better Auth URL with path /api/auth/oauth2/callback/square on the same origin as BETTER_AUTH_URL.

For more details, see the Deployment guide in the Next.js section.