2026-02-21 09:54:14 -05:00
---
name : firebase-app-platform
2026-03-24 18:02:50 -04:00
description : Build and operate apps on Firebase using Auth, Firestore, Cloud Functions, and Hosting. Use when building mobile/web backends with managed services, real-time data sync, or serverless APIs.
2026-02-21 09:54:14 -05:00
license : MIT
metadata :
author : devops-skills
version : "1.0"
---
# Firebase App Platform
Ship mobile and web backends with Firebase managed services.
2026-03-24 18:02:50 -04:00
## When to Use This Skill
Use this skill when:
- Building mobile or web apps with real-time data sync
- Need authentication with minimal backend code
- Prototyping quickly with managed infrastructure
- Building serverless APIs with Cloud Functions
- Hosting static sites or SPAs with CDN
## Prerequisites
- Node.js 18+
- Firebase CLI (`npm install -g firebase-tools` )
- Google Cloud account (Firebase is part of GCP)
- A Firebase project (create at console.firebase.google.com)
## Quick Start
2026-02-21 09:54:14 -05:00
```bash
2026-03-24 18:02:50 -04:00
# Install and authenticate
2026-02-21 09:54:14 -05:00
npm install -g firebase-tools
firebase login
2026-03-24 18:02:50 -04:00
# Initialize in your project directory
2026-02-21 09:54:14 -05:00
firebase init
2026-03-24 18:02:50 -04:00
# Select: Firestore, Functions, Hosting, Emulators
# Start local emulators
firebase emulators:start
# Deploy everything
2026-02-21 09:54:14 -05:00
firebase deploy
2026-03-24 18:02:50 -04:00
# Deploy specific services
firebase deploy --only functions
firebase deploy --only hosting
firebase deploy --only firestore:rules
2026-02-21 09:54:14 -05:00
```
2026-03-24 18:02:50 -04:00
## Firestore Database
2026-02-21 09:54:14 -05:00
2026-03-24 18:02:50 -04:00
### Security Rules
```javascript
// firestore.rules
rules_version = '2' ;
service cloud . firestore {
match / databases / { database } / documents {
// Users can only read/write their own data
match / users / { userId } {
allow read , write : if request . auth != null && request . auth . uid == userId ;
}
// Messages: authenticated users can read, only owner can write
match / channels / { channelId } / messages / { messageId } {
allow read : if request . auth != null ;
allow create : if request . auth != null
&& request . resource . data . userId == request . auth . uid
&& request . resource . data . body is string
&& request . resource . data . body . size () <= 5000 ;
allow update , delete : if request . auth != null
&& resource . data . userId == request . auth . uid ;
}
// Admin-only collection
match / admin / { document =** } {
allow read , write : if request . auth != null
&& get ( /databases/ $ ( database ) / documents / users / $ ( request . auth . uid )). data . role == 'admin' ;
}
// Default: deny everything
match / { document =** } {
allow read , write : if false ;
}
}
}
```
### Data Operations
```typescript
// lib/firestore.ts
import { getFirestore , collection , doc , setDoc , getDoc ,
query , where , orderBy , limit , onSnapshot ,
serverTimestamp , increment } from "firebase/firestore" ;
const db = getFirestore ();
// Create document with auto-ID
async function createMessage ( channelId : string , body : string , userId : string ) {
const ref = doc ( collection ( db , "channels" , channelId , "messages" ));
await setDoc ( ref , {
body ,
userId ,
createdAt : serverTimestamp (),
});
return ref . id ;
}
// Real-time listener
function subscribeToMessages ( channelId : string , callback : ( msgs : any []) => void ) {
const q = query (
collection ( db , "channels" , channelId , "messages" ),
orderBy ( "createdAt" , "desc" ),
limit ( 50 )
);
return onSnapshot ( q , ( snapshot ) => {
const messages = snapshot . docs . map ( doc => ({ id : doc.id , ... doc . data () }));
callback ( messages );
});
}
// Atomic counter
async function incrementViews ( postId : string ) {
await setDoc ( doc ( db , "posts" , postId ), {
views : increment ( 1 ),
}, { merge : true });
}
```
### Indexes
```json
// firestore.indexes.json
{
"indexes" : [
{
"collectionGroup" : "messages" ,
"queryScope" : "COLLECTION" ,
"fields" : [
{ "fieldPath" : "channelId" , "order" : "ASCENDING" },
{ "fieldPath" : "createdAt" , "order" : "DESCENDING" }
]
}
]
}
```
## Authentication
```typescript
// lib/auth.ts
import { getAuth , signInWithPopup , GoogleAuthProvider ,
createUserWithEmailAndPassword , signInWithEmailAndPassword ,
signOut , onAuthStateChanged } from "firebase/auth" ;
const auth = getAuth ();
// Google sign-in
async function signInWithGoogle() {
const provider = new GoogleAuthProvider ();
const result = await signInWithPopup ( auth , provider );
return result . user ;
}
// Email/password registration
async function register ( email : string , password : string ) {
const result = await createUserWithEmailAndPassword ( auth , email , password );
return result . user ;
}
// Auth state listener
onAuthStateChanged ( auth , ( user ) => {
if ( user ) {
console . log ( "Signed in:" , user . uid , user . email );
} else {
console . log ( "Signed out" );
}
});
```
## Cloud Functions
```typescript
// functions/src/index.ts
import { onRequest } from "firebase-functions/v2/https" ;
import { onDocumentCreated } from "firebase-functions/v2/firestore" ;
import { getFirestore } from "firebase-admin/firestore" ;
import { initializeApp } from "firebase-admin/app" ;
initializeApp ();
const db = getFirestore ();
// HTTP function (API endpoint)
export const api = onRequest ({ cors : true , region : "us-central1" }, async ( req , res ) => {
if ( req . method !== "GET" ) {
res . status ( 405 ). send ( "Method not allowed" );
return ;
}
const snapshot = await db . collection ( "posts" ). orderBy ( "createdAt" , "desc" ). limit ( 10 ). get ();
const posts = snapshot . docs . map ( doc => ({ id : doc.id , ... doc . data () }));
res . json ({ posts });
});
// Firestore trigger — runs when a new message is created
export const onMessageCreated = onDocumentCreated (
"channels/{channelId}/messages/{messageId}" ,
async ( event ) => {
const data = event . data ? . data ();
if ( ! data ) return ;
// Update channel's last message timestamp
await db . doc ( `channels/ ${ event . params . channelId } ` ). update ({
lastMessageAt : data.createdAt ,
messageCount : FieldValue.increment ( 1 ),
});
// Send notification (example)
console . log ( `New message in ${ event . params . channelId } : ${ data . body . substring ( 0 , 50 ) } ` );
}
);
```
## Hosting
```json
// firebase.json
{
"hosting" : {
"public" : "dist" ,
"ignore" : [ "firebase.json" , "**/.*" , "**/node_modules/**" ],
"rewrites" : [
{ "source" : "/api/**" , "function" : "api" },
{ "source" : "**" , "destination" : "/index.html" }
],
"headers" : [
{
"source" : "**/*.@(js|css|svg|png|jpg|webp|woff2)" ,
"headers" : [{ "key" : "Cache-Control" , "value" : "public, max-age=31536000, immutable" }]
},
{
"source" : "**" ,
"headers" : [
{ "key" : "X-Frame-Options" , "value" : "DENY" },
{ "key" : "X-Content-Type-Options" , "value" : "nosniff" },
{ "key" : "Strict-Transport-Security" , "value" : "max-age=63072000" }
]
}
]
}
}
```
## Local Emulators
```bash
# Start all emulators
firebase emulators:start
# Start specific emulators
firebase emulators:start --only auth,firestore,functions
# Export emulator data for persistence
firebase emulators:export ./emulator-data
firebase emulators:start --import= ./emulator-data
# Emulator UI at http://localhost:4000
```
```json
// firebase.json — emulator config
{
"emulators" : {
"auth" : { "port" : 9099 },
"firestore" : { "port" : 8080 },
"functions" : { "port" : 5001 },
"hosting" : { "port" : 5000 },
"ui" : { "enabled" : true , "port" : 4000 }
}
}
```
## Environment Configuration
```bash
# Set environment variables for functions
firebase functions:config:set stripe.key= "sk_live_xxx" app.name= "MyApp"
# View config
firebase functions:config:get
# Use in functions (v1)
const stripeKey = functions.config() .stripe.key;
# For v2 functions, use .env files
# functions/.env
STRIPE_KEY = sk_live_xxx
# functions/.env.local (for emulators)
STRIPE_KEY = sk_test_xxx
```
## Multi-Environment Setup
```bash
# Create separate projects for each environment
firebase use --add # Add staging project alias
firebase use staging # Switch to staging
firebase use production
# Deploy to specific project
firebase deploy --project my-app-staging
firebase deploy --project my-app-production
# .firebaserc
{
"projects" : {
"staging" : "my-app-staging" ,
"production" : "my-app-production"
}
}
```
## CLI Reference
```bash
firebase projects:list # List all projects
firebase deploy # Deploy everything
firebase deploy --only functions # Deploy only functions
firebase deploy --only hosting # Deploy only hosting
firebase deploy --only firestore # Deploy rules + indexes
firebase functions:log # View function logs
firebase hosting:channel:create pr-123 # Preview channel
firebase hosting:channel:delete pr-123
```
## Security Best Practices
- Write strict Firestore security rules before any other code
- Separate environments by Firebase project (staging/production)
- Enable budget alerts and quota monitoring in GCP console
- Move privileged logic into Cloud Functions (never trust the client)
- Use App Check to prevent API abuse from non-app clients
- Enable Firestore audit logging for compliance
- Review OAuth consent screen settings
## Troubleshooting
| Issue | Solution |
|-------|---------|
| Permission denied | Check Firestore rules, verify auth state |
| Function cold starts | Use min instances (`minInstances: 1` ), optimize imports |
| Emulator won't start | Check port conflicts, run `firebase emulators:start --debug` |
| Deploy fails | Run `firebase deploy --debug` , check service account permissions |
| Rules test failing | Use `firebase emulators:exec` to run rules unit tests |
2026-02-21 09:54:14 -05:00
## Related Skills
2026-03-24 18:02:50 -04:00
- [gcp-cloud-functions ](../../cloud-gcp/gcp-cloud-functions/ ) — Function runtime patterns
- [vercel-deployments ](../vercel-deployments/ ) — Alternative frontend hosting
- [convex-backend ](../convex-backend/ ) — Alternative managed backend