Quick Start
Clone, configure Firebase, set environment variables, and run the store locally.
Get the boilerplate running locally in a few minutes. The store is quote-based by default — shoppers browse the catalog, build a cart, and submit a quote request. No payment processor, email provider, or SQL database is required to boot; those are all optional and env-gated. The only thing you need to configure is Firebase, which provides authentication and the default Firestore data layer.
Prerequisites
- Node.js 20 or newer. The
firebase-adminv14 SDK used by the seed script and the optional Stripe webhook requires Node 20+. - npm (ships with Node).
- A Google account to create a free Firebase project.
This guide covers the zero-config Firebase default. Swapping to a SQL backend (Supabase or Postgres/Prisma) is optional and layered on afterward — see Choosing a backend. You do not need Prisma, a DATABASE_URL, or any SQL setup to run the store.
Steps
Clone and install
git clone <this-repo>
cd ecommerce-boilerplate
npm installnpm install runs a postinstall step (fumadocs-mdx) that generates the type definitions for these docs — that is expected.
Create a Firebase project
- Create a project at console.firebase.google.com.
- Add a Web app and copy its config values (you will paste them into
.env.localnext). - Enable Authentication → sign-in methods: Google and Email link (passwordless).
- Enable Cloud Firestore.
Both sign-in methods are used by the storefront: Google sign-in and passwordless email-link sign-in. Customer records are created in the customers collection on first login.
Configure environment variables
Copy the example file and fill in your Firebase web-app values:
cp .env.example .env.localThe only variables you must set to run the store are the Firebase NEXT_PUBLIC_* values plus the email sign-in redirect URL:
| Variable | Value |
|---|---|
NEXT_PUBLIC_FIREBASE_API_KEY | From your Firebase web-app config |
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN | e.g. your-project.firebaseapp.com |
NEXT_PUBLIC_FIREBASE_PROJECT_ID | e.g. your-project |
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET | e.g. your-project.appspot.com |
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID | From your Firebase web-app config |
NEXT_PUBLIC_FIREBASE_APP_ID | From your Firebase web-app config |
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID | Optional (Analytics) |
NEXT_PUBLIC_EMAIL_SIGNIN_REDIRECT_URL | http://localhost:3000/complete-login in development |
Set the redirect URL for local development:
NEXT_PUBLIC_EMAIL_SIGNIN_REDIRECT_URL=http://localhost:3000/complete-loginThe passwordless email-link sign-in returns the visitor to this absolute URL to finish signing in. In production, set it to your live URL (e.g. https://yourstore.com/complete-login) and make sure that domain is listed under Firebase Auth → Settings → Authorized domains.
Firebase web credentials are safe to expose to the browser. The NEXT_PUBLIC_* keys are designed to be public — access control is enforced by the shipped firestore.rules, not by hiding the keys. See the environment variables reference for the full list, including the optional Stripe, Resend, and SQL-backend variables.
Run the dev server
npm run devOpen http://localhost:3000. The storefront renders immediately — the landing page, header, and navigation all work right away. Product grids stay empty until you add catalog data, either by seeding demo data (next step) or by creating products in the admin dashboard.
(Optional) Seed demo data
The repo ships a seed script that fills Firestore with 18 demo products (3 per category, matching the slugs in src/config/site.ts) and features 6 of them on the home page. Two of the products carry variants (a size axis and a color axis with a price override) so the variant UI is demoable.
Because firestore.rules blocks client-side writes to the products collection, the script uses the Firebase Admin SDK and needs a service-account key.
First, preview the plan — this needs no credentials and writes nothing:
npm run seed -- --dry-runThen get a key from Firebase console → Project settings → Service accounts → Generate new private key, save it outside the repo (it is git-ignored; never commit it), and point the script at it with either variable:
FIREBASE_SERVICE_ACCOUNT=/path/to/service-account.json npm run seed
# or, using Google application-default credentials:
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json npm run seedThe project id is read from the service-account JSON automatically. With application-default credentials, set FIREBASE_PROJECT_ID (or rely on NEXT_PUBLIC_FIREBASE_PROJECT_ID from .env.local). The script is idempotent: products use deterministic ids and are overwritten in place, and featured copies are cleaned up before being re-added, so re-running never creates duplicates.
No service account yet? Skip this step and create products from the admin dashboard instead — you just need admin access first (next step).
Grant yourself admin access
The admin dashboard lives at /admin and is gated by a role — being signed in is not enough. Access is granted by adding your user id to the admins collection in Firestore:
- Sign in to the store once at http://localhost:3000/login so your user exists in Firebase Auth.
- In Firestore, create a document in the
adminscollection whose document id is your user id (shown on the/adminaccess-denied screen, or in Firebase Auth → Users). The document body can be empty. - Reload — the Admin entry appears in the account menu, and
/adminunlocks.
Clients can never write to the admins collection — manage it only from the Firebase console. In firestore.rules, the admins/{uid} match allows read: if isOwner(uid) and write: if false; the isAdmin() helper checks for a document at admins/{request.auth.uid}. The in-app UI check (useIsAdmin) is convenience only — real enforcement lives in the rules, so deploy them before going to production with firebase deploy --only firestore:rules.
What you get out of the box
With Firebase configured and (optionally) demo data seeded, you have a working store:
- Storefront at
/— landing page, catalog with category filtering, and product detail pages. - Cart & quotes — guest carts in
localStorage, signed-in carts synced to thecartscollection in Firestore, and a quote-request checkout that writes to thequotescollection (status starts as"Pending"). - Account area at
/account— profile, addresses, and quote/order history. - Admin dashboard at
/admin— product CRUD, featured curation, the quote pipeline, order fulfillment, customers, and analytics.
Stripe payments, Resend email notifications, and SQL backends stay dormant until you set their env vars — the store works fully without any of them.