Acme Store Docs
Configuration

Environment Variables

Complete reference for every environment variable and the feature it controls.

The boilerplate is configured entirely through environment variables. Copy the template and fill in the values you need:

Terminal
cp .env.example .env.local

Only the Firebase web credentials and the email sign-in redirect URL are required for a working default deployment. Everything else is optional and feature-gated: leaving an optional variable empty disables that feature gracefully, with no crash and no build failure. The store's default mode is quote-based (browse → cart → submit a quote request), so payments, transactional email, and SQL backends all stay off until you opt in.

Variables prefixed with NEXT_PUBLIC_ are inlined into the browser bundle at build time and are public by design. Never give that prefix to a secret. All other variables are server-only and never reach the client.

Quick reference

VariableRequiredFeature
NEXT_PUBLIC_FIREBASE_API_KEYYesFirebase / Auth / Firestore
NEXT_PUBLIC_FIREBASE_AUTH_DOMAINYesFirebase Auth
NEXT_PUBLIC_FIREBASE_PROJECT_IDYesFirebase project
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKETYesFirebase Storage
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_IDYesFirebase
NEXT_PUBLIC_FIREBASE_APP_IDYesFirebase
NEXT_PUBLIC_FIREBASE_MEASUREMENT_IDOptionalFirebase Analytics
NEXT_PUBLIC_EMAIL_SIGNIN_REDIRECT_URLYesPasswordless email sign-in
RESEND_API_KEYOptionalQuote/status email notifications
RESEND_FROM_EMAILOptionalEmail sender address
QUOTE_NOTIFICATION_EMAILOptionalNew-quote notification inbox
FIREBASE_SERVICE_ACCOUNTOptionalnpm run seed, server-side Firestore
STRIPE_SECRET_KEYOptionalStripe Checkout
STRIPE_WEBHOOK_SECRETOptionalStripe webhook verification
FIREBASE_SERVICE_ACCOUNT_JSONOptionalWebhook / server-side Firestore writes
NEXT_PUBLIC_COMMERCE_BACKENDOptionalBrowser commerce adapter (default firebase)
COMMERCE_BACKENDOptionalServer commerce adapter
SUPABASE_URLOptionalSupabase backend
SUPABASE_SERVICE_ROLE_KEYOptionalSupabase backend
DATABASE_URLOptionalPostgres/Prisma backend

Firebase web credentials

Firebase is the default identity provider and the default commerce backend. These seven values come from the Firebase console → Project settings → Your apps. They are NEXT_PUBLIC_* because Firebase web credentials are meant to be public — access control lives in your Firestore security rules, not in these keys.

VariableRequiredExampleDescription
NEXT_PUBLIC_FIREBASE_API_KEYYes(from console)Web API key for the Firebase JS SDK.
NEXT_PUBLIC_FIREBASE_AUTH_DOMAINYesyour-project.firebaseapp.comAuth domain used by the sign-in flow.
NEXT_PUBLIC_FIREBASE_PROJECT_IDYesyour-projectFirebase / Google Cloud project ID.
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKETYesyour-project.appspot.comStorage bucket for uploaded assets.
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_IDYes(from console)Cloud Messaging sender ID.
NEXT_PUBLIC_FIREBASE_APP_IDYes(from console)Firebase web app ID.
NEXT_PUBLIC_FIREBASE_MEASUREMENT_IDOptional(from console)Google Analytics measurement ID; omit to skip analytics.

Email sign-in redirect

The storefront uses Firebase passwordless (email-link) sign-in. After a user clicks the link in their inbox, Firebase redirects them back to this absolute URL to complete authentication.

VariableRequiredExampleDescription
NEXT_PUBLIC_EMAIL_SIGNIN_REDIRECT_URLYeshttp://localhost:3000/complete-loginAbsolute URL the email sign-in link returns to. Consumed by src/lib/firebase/authService.ts.

The host in this URL must be listed under Firebase Auth → Settings → Authorized domains, or the redirect is rejected. In production, point it at your deployed domain's /complete-login route.

Resend email notifications (optional)

Transactional email is powered by Resend and is entirely optional. When RESEND_API_KEY is empty, the POST /api/quotes/notify and POST /api/notifications/status endpoints skip sending and respond { skipped: true } — the quote flow itself is unaffected.

VariableRequiredDefaultDescription
RESEND_API_KEYOptional(empty → email disabled)Resend API key. Leaving it empty disables all outgoing email.
RESEND_FROM_EMAILOptionalonboarding@resend.devVerified sender address. Falls back to Resend's shared testing sender when unset.
QUOTE_NOTIFICATION_EMAILOptionalsiteConfig.contact.emailInbox that receives new-quote notifications. Falls back to the site contact email.

The fallbacks are applied server-side in src/app/api/quotes/notify/route.ts:

src/app/api/quotes/notify/route.ts
const from = process.env.RESEND_FROM_EMAIL || "onboarding@resend.dev";
const adminRecipient =
  process.env.QUOTE_NOTIFICATION_EMAIL || siteConfig.contact.email;

Seed service account (optional)

npm run seed (see scripts/seed.mjs) needs Firebase Admin credentials to write seed data into Firestore. Point this at a service-account JSON file downloaded from the Firebase console → Project settings → Service accounts → Generate new private key.

VariableRequiredExampleDescription
FIREBASE_SERVICE_ACCOUNTOptional./firebase-service-account.jsonFilesystem path to a service-account JSON key. Also used by firebase-admin for server-side Firestore writes and ID-token verification.

Never commit the service-account file, and never expose it with a NEXT_PUBLIC_ prefix — it grants privileged, RLS-bypassing access to your project. Keep it server-side only.

Stripe Checkout (optional)

Stripe adds a real "Checkout" button alongside the quote flow. The Stripe client is instantiated lazily (src/lib/stripe.ts), so when STRIPE_SECRET_KEY is unset the store stays quote-only and the Checkout button simply does not appear.

src/lib/stripe.ts
export function isStripeEnabled(): boolean {
  return Boolean(process.env.STRIPE_SECRET_KEY);
}
VariableRequiredDescription
STRIPE_SECRET_KEYOptionalStripe secret key. Enables Checkout; leave empty to keep the store quote-only.
STRIPE_WEBHOOK_SECRETOptionalSigning secret used to verify the POST /api/webhooks/stripe endpoint (from stripe listen or the dashboard).
FIREBASE_SERVICE_ACCOUNT_JSONOptionalService-account JSON contents (not a path). Lets the Stripe webhook record orders server-side. Vercel-friendly; alternatively rely on FIREBASE_SERVICE_ACCOUNT.

FIREBASE_SERVICE_ACCOUNT_JSON holds the raw private-key JSON. Treat it as a secret: server-only, never NEXT_PUBLIC_, never committed.

Commerce backend selection

The commerce data layer (src/lib/commerce) is backend-agnostic. Firebase is the default and runs entirely client-side. Selecting a SQL backend routes the browser through the /api/commerce RPC route, where a privileged server adapter runs. Firebase Auth stays the identity provider for every backend — its ID token is verified server-side via firebase-admin, so the FIREBASE_SERVICE_ACCOUNT* credentials are required for the SQL backends too.

Two variables must agree:

VariableRequiredDefaultDescription
NEXT_PUBLIC_COMMERCE_BACKENDOptionalfirebaseWhich adapter the browser uses.
COMMERCE_BACKENDOptional(empty → firebase)Which server adapter the /api/commerce RPC route resolves.
  • firebase (or unset): pure client-side Firebase — no RPC route, no SQL variables needed.
  • supabase | postgres: set both variables to the same value and provide the matching credentials below.

NEXT_PUBLIC_COMMERCE_BACKEND and COMMERCE_BACKEND must name the same backend. The public one tells the browser which adapter to load; the server one gates the RPC route. A mismatch means the browser talks to a route that refuses its requests.

Supabase adapter

Set when COMMERCE_BACKEND=supabase. Values come from Supabase → Project Settings → API. See the Supabase adapter guide.

VariableRequiredExampleDescription
SUPABASE_URLWith Supabasehttps://your-project-ref.supabase.coSupabase project URL.
SUPABASE_SERVICE_ROLE_KEYWith Supabase(from dashboard)Service-role key used by the server adapter.

Never prefix the Supabase variables with NEXT_PUBLIC_. The service-role key bypasses Row Level Security and must never reach the browser.

Postgres / Prisma adapter

Set when COMMERCE_BACKEND=postgres. Read by both the Prisma CLI (prisma.config.ts) and the runtime adapter (src/lib/commerce/server/prisma.ts). See the Postgres/Prisma adapter guide.

VariableRequiredExampleDescription
DATABASE_URLWith Postgrespostgresql://user:password@localhost:5432/ecommercePlain PostgreSQL connection string (local, Supabase pooler, Neon, RDS, …).

This project does not use Prisma Postgres / Accelerate — you never need a Prisma account or API key. Set DATABASE_URL to a real postgresql:// URL before running npm run prisma:generate, otherwise the Prisma CLI drops into its hosted-DB onboarding and asks for an API key. Not using Postgres? Leave it blank.

On this page