What you need first
Node.js 22+ and
pnpminstalled locally.A Firebase project (create one in the Firebase console).
Firebase CLI installed:
npm install -g firebase-tools
Link the repo to your Firebase project
From the repository root, log in and connect the project.
firebase login
firebase use --addThis creates or updates .firebaserc with your default project id.
{
"projects": {
"default": "your-firebase-project-id"
}
}Configure Next.js for static export
Firebase Hosting serves static files. In packages/next-frontend/next.config.ts, enable static export and set the output folder to dist.
const nextConfig = {
output: "export",
distDir: "dist",
trailingSlash: true,
};Run pnpm --filter @22c-publishing-platform/next-frontend build and confirm the site is generated in packages/next-frontend/dist.
Configure Firebase hosting and deployment scripts
Add the hosting section to your root firebase.json.
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"hosting": {
"public": "packages/next-frontend/dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
},
"storage": {
"rules": "storage.rules"
}
}Add deploy scripts to the root package.json. The predeploy step builds shared packages before the frontend.
{
"scripts": {
"deploy": "firebase deploy",
"predeploy": "pnpm --filter @22c-publishing-platform/component-library build &&\n pnpm --filter @22c-publishing-platform/next-frontend build"
}
}Set environment variables for the frontend build
Create packages/next-frontend/.env with your Firebase web app config (Firebase console → Project settings → Your apps).
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=These values are baked into the static build, so set them before running pnpm run deploy.
Deploy Firestore, Storage rules, and indexes
Keep these files up to date in the repo root:
firestore.rules— database security rulesfirestore.indexes.json— composite indexes used by queriesstorage.rules— Cloud Storage security rules
firebase deploy publishes hosting, rules, and indexes together. To deploy only hosting during a quick UI check:
firebase deploy --only hostingTo deploy only rules or indexes:
firebase deploy --only firestore:rules,firestore:indexes,storageDeploy locally
From the repository root:
pnpm install
pnpm run deployThe predeploy script builds the component library and Next.js app, then Firebase CLI uploads the dist folder and applies rules.
When deployment finishes, open the Hosting URL shown in the terminal (or Firebase console → Hosting).
Set up the GitHub deployment pipeline
Add these repository secrets in GitHub (Settings → Secrets and variables → Actions):
FIREBASE_TOKEN=
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=Generate FIREBASE_TOKEN locally with:
firebase login:ciCopy the token into the GitHub secret named FIREBASE_TOKEN.
Add the deployment workflow to .github/workflows/deploy.yml.
name: Deploy Firebase
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v6
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: "22"
cache: "pnpm"
- name: Install Firebase CLI
run: npm install -g firebase-tools
- name: Install dependencies
run: pnpm install
- run: pnpm run deploy
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
NEXT_PUBLIC_FIREBASE_API_KEY: ${{ secrets.NEXT_PUBLIC_FIREBASE_API_KEY }}
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN: ${{ secrets.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN }}
NEXT_PUBLIC_FIREBASE_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_PROJECT_ID }}
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET: ${{ secrets.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET }}
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID }}
NEXT_PUBLIC_FIREBASE_APP_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_APP_ID }}
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID }}
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: ${{ secrets.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY }}Push to main to trigger a production deploy. Check the Actions tab if a deploy fails.
After deployment
Open the live Hosting URL and smoke-test key pages.
In Firebase console, confirm Firestore indexes show as Enabled (new indexes can take a few minutes).
Re-run deploy whenever you change
firestore.rules,storage.rules, orfirestore.indexes.json.
