Deployment
Personal Catalogue: React & Firebase
Chapter 9 · Deployment
This chapter gets the whole app running as a real standalone deployment — Chapter 10's own capstone handles the more specific question of mounting it inside the user's existing Astro-based site. Getting there is dramatically shorter than any of this project's three siblings, for one direct, cumulative reason: this course never built a server of its own to deploy in the first place.
A Genuinely Simpler Deployment — By Design, Not by Luck
| Production concern | The MongoDB sibling needs | This course needs |
|---|---|---|
| A running backend process | Express, kept alive with PM2 | Nothing — Firestore is already a running, managed service |
| Cross-origin request handling | CORS middleware, tightened for production | Nothing — the Firestore client SDK isn't a cross-origin request in the CORS sense at all |
| A public-facing reverse proxy | nginx, for a real domain and TLS termination | Nothing — Firebase Hosting provides both directly |
| A scoped, least-privilege database account | A dedicated MongoDB user with a readWrite-only role | Nothing new — already done, as Security Rules, back in Chapters 3 and 5 |
| Serving the built frontend | express.static(), from the same process as the API | Firebase Hosting — a dedicated static-file CDN |
None of this is a shortcut this course is taking — it's the direct, cumulative consequence of Chapter 3's own real decision that this app never needed a backend server at all.
Isolating Dev From Production: a Different Reason for Env Variables Than the MongoDB Sibling's
The MongoDB sibling's own Chapter 9 moves six hardcoded localhost:4000 URLs into one
environment-driven constant, because a real production domain has to replace a literal development address.
This course has no API URLs to centralize — there's no backend of its own to point at. What genuinely is
worth moving into environment variables here is something different: the Firebase project config itself,
so a production build can point at a completely separate Firebase project than local development uses,
keeping real production data untouched by anything built or tested locally.
npm run dev and a real production build can point at two
genuinely separate Firebase projects, so testing locally never risks touching or corrupting real catalogue
data.
Building & Deploying to Firebase Hosting
Vite's default build writes a real, deployable set of static files into dist/. Firebase Hosting
is configured once, per project, to serve exactly that folder:
rewrites option exists for the same reason most SPA-hosting setups need
one: a real client-side route like /books/123 would otherwise 404 on a hard refresh, since no
static file at that exact path exists. This app never had a client-side route at all — Chapter 7's own
list/detail toggle is pure component state, never a URL change — so this rule, while harmless to include,
never actually has anything to rewrite in practice.
What This Course Never Needed to Build
No CORS configuration exists anywhere in this app, in any chapter — the Firestore client SDK talks to Firebase's own servers using its own protocol, not a same-origin-restricted browser fetch, so there was never a cross-origin policy of this app's own to write in the first place. No PM2, because there is no long-running process of this course's own to keep alive; Firestore and Firebase Hosting are already running, managed services maintained by Firebase itself. No nginx reverse proxy, because Firebase Hosting already terminates TLS and serves the app directly.
hasValidBaseFields()/hasTypeRequiredFields()/hasValidResolution() and
Chapter 5's own tagsOnlyOnBooks() are this app's real access-control layer, and nothing new needs
to be written here to reach production — only confirming those rules are actually deployed to the real
production project, not just the development one used throughout this course so far.
Automatic HTTPS, for Free
Firebase Hosting provisions and renews a free SSL certificate automatically for both its own
*.web.app subdomain and any real custom domain connected to the project — no certificate
request, no renewal cron job, and no dedicated reverse proxy layer required to get it, unlike the MongoDB
sibling's own nginx-plus-certificate setup.
Scheduled Backups, the Managed Way
The MongoDB sibling schedules a real mongodump cron job to keep a dated snapshot on disk,
independent of whatever a hosting provider's own backup story does or doesn't cover. Firestore offers a real,
equivalent managed feature — scheduled backups, configured directly through Google Cloud rather than a
self-written script:
The same underlying need — a dated snapshot existing independently of the live database, in case something ever needs to be restored — solved here by configuring a managed service once, rather than maintaining a script and a cron entry indefinitely.
Trying It
Visiting the real https://catalogue-prod.web.app URL Firebase prints after deployment should
load the working catalogue app directly, with every action — search, add, tag edit — succeeding exactly as it
did throughout development, now reading from and writing to the real production Firestore project instead of
the development one.
Hands-On Exercises
Move the Firebase config in firebase.js into VITE_-prefixed environment variables, create separate .env.development and .env.production files pointing at two different real Firebase projects, and confirm npm run dev connects to the development project while a production build connects to the other.
📄 View solutionBuild the app, configure firebase.json for Hosting, and deploy it with firebase deploy --only hosting. Confirm the real, live URL Firebase provides loads the working app and that a real add-item action succeeds against the deployed site.
📄 View solutionExplain, for each of CORS, PM2, and a reverse proxy, precisely why this course never needed to build it — tying each answer back to a specific earlier architectural decision rather than a general "Firebase handles it" claim.
📄 View solutionChapter 9 Quick Reference
- No backend to deploy — the direct, cumulative payoff of Chapter 3's own no-server decision
- Env-driven Firebase config — for real dev/prod project isolation, not for secrecy (Chapter 1 already settled that question)
- Firebase Hosting — npm run build, then firebase deploy --only hosting
- The SPA rewrite rule is a no-op here too — the same real reason as Chapter 7's own missing fallback route: no client-side routing exists in this app at all
- Never needed — CORS, PM2, an nginx reverse proxy, a dedicated database user (Security Rules already cover that job, done back in Chapters 3 and 5)
- Free, automatic HTTPS — provisioned and renewed by Firebase Hosting itself
- Managed backups — Firestore's own scheduled backup feature, configured once rather than maintained as a cron script
- Next chapter: Capstone — integrating the catalogue into the existing Astro site, and comparing self-managed MongoDB against managed Firestore across the whole project