This repository is a full-stack monorepo template using npm workspaces and Turborepo to manage a React frontend and a NestJS backend in a single repository.
It is based on a minimal monorepo foundation, with Google authentication pre-wired using Firebase so you don’t have to build auth plumbing from scratch.
This is a template, not a production-ready system.
This template provides:
- A correct, minimal monorepo setup
- Clear separation of frontend and backend concerns
- Centralized dependency management
- Coordinated development scripts
- Working Google OAuth (Firebase) across frontend and backend
Authentication is included, but only to the extent required to:
- Sign users in with Google on the frontend
- Verify and trust those users on the backend
Everything else remains intentionally unopinionated.
This template does not try to be a full application starter.
It does not include:
- User roles or permissions
- Auth-based authorization rules
- Session persistence strategies
- Database schemas or migrations
- API clients or shared domain models
- Deployment, Docker, or CI/CD
Those decisions are left to the user.
.
├── apps/
│ ├── backend/ # NestJS backend (Firebase Admin + JWT + Mongo)
│ └── frontend/ # React + Vite + Tailwind (Firebase client)
├── packages/ # Optional shared packages (empty by default)
├── package.json # Root workspace + Turbo configuration
├── package-lock.json # Single lockfile for the entire monorepo
├── turbo.json # Turbo task pipeline
└── README.md
- This is a monorepo
- Dependency management is centralized at the root
- Each app remains a standalone project
- No shared code is assumed
- Shared packages are optional and explicit
- NestJS
- TypeScript
- Firebase Admin SDK
- JWT-based session tokens
- MongoDB (wired, no schemas assumed)
- React
- Vite
- TailwindCSS
- TypeScript
- Firebase Client SDK (Google sign-in)
- npm workspaces
- Turborepo
You need:
- Node.js (LTS recommended)
- npm (v7+ for workspaces)
From the repository root:
npm installThis installs dependencies for all workspace packages and generates a single package-lock.json.
Do not run npm install inside individual apps.
Run all development servers concurrently:
npm run devThis uses Turbo to:
- Start the NestJS backend
- Start the Vite frontend
- Stream logs with app prefixes
- Backend:
http://localhost:3000 - Frontend:
http://localhost:5173
This template will not start unless required environment variables are present and valid.
Both frontend and backend rely on Firebase, but for different purposes:
- Frontend → Firebase client SDK
- Backend → Firebase Admin SDK
If the backend crashes with:
SyntaxError: "undefined" is not valid JSON
at JSON.parse (<anonymous>)
at firebase.module.ts
The backend expects a Firebase service account JSON via:
JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT)If the variable is missing, misnamed, or malformed, the process crashes immediately.
You must provide a valid Firebase service account JSON via the
FIREBASE_SERVICE_ACCOUNT environment variable, wrapped in single quotes.
You may also see an error similar to:
MongoParseError: URI must be provided
or:
MongooseError: The `uri` parameter to `openUri()` must be a string
This error simply means that no MongoDB connection string was provided.
The backend expects a MongoDB URI via the MONGO_URI environment variable.
If it’s missing, empty, or misspelled, Nest will fail during startup.
This error is not related to Firebase or Google Auth.
Make sure your backend .env file includes:
MONGO_URI=mongodb_connection_stringThis can be:
-
A local MongoDB instance
mongodb://localhost:27017/your-db-name -
Or a hosted provider (e.g. MongoDB Atlas)
Once MONGO_URI is defined, the backend should start normally.
Create a .env file in apps/backend:
JWT_SECRET=your_jwt_secret_here
JWT_EXPIRES=604800000
PORT=3000
NODE_ENV=development
FRONTEND_URL=http://localhost:5173
MONGO_URI=mongodb_connection_string
FIREBASE_SERVICE_ACCOUNT='{ ... }'-
JWT_EXPIRESmust be a number, not a string -
NODE_ENVmust bedevelopmentfor local dev -
FIREBASE_SERVICE_ACCOUNTmust:- Be valid JSON
- Be wrapped in single quotes
- Contain the entire service account object
Example (truncated):
FIREBASE_SERVICE_ACCOUNT='{
"type": "service_account",
"project_id": "your-project-id",
"private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
"client_email": "firebase-adminsdk@your-project-id.iam.gserviceaccount.com"
}'Create a .env file in apps/frontend:
VITE_BACKEND_BASE_URL=http://localhost:3000
VITE_FIREBASE_API_KEY=your_api_key
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_id
VITE_BACKEND_URL=http://localhost:3000These values come from your Firebase Web App configuration, not the service account.
- Firebase Console → Add project
- Authentication → Sign-in method → Enable Google
- Project Settings → Web app
- Copy config into frontend
.env
- Project Settings → Service accounts
- Generate new private key
- Paste JSON into
FIREBASE_SERVICE_ACCOUNT - Wrap in single quotes
Even with auth included:
- Frontend and backend are not tightly coupled
- They can be deployed independently
- No shared packages are required
- API communication is explicit
Auth establishes trust, not architectural dependency.
Turbo operates on script names, not commands.
If an app doesn’t define dev, build, or lint, Turbo skips it.
Turbo is used only for:
- Task orchestration
- Caching
- Parallel execution
It does not enforce architecture.