Skip to main content
skill CX Codex

firebase-app-platform — Claude Code skill: Firebase backend

A skill that walks your agent through Firebase backends: Auth, Firestore, Cloud Functions and Hosting. Useful when you want managed services instead of your own server.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add BagelHole/DevOps-Security-Agent-Skills --skill firebase-app-platform -a claude-code
Open on GitHub

What firebase-app-platform does

The skill covers Firebase managed services: Firestore security rules, data operations, authentication, Cloud Functions and static hosting. It ships TypeScript and JavaScript examples plus configs for firestore.rules, firestore.indexes.json and firebase.json.

You need Node.js 18+, the Firebase CLI and a Firebase project. Install the CLI with npm install -g firebase-tools, then run firebase login and firebase init, picking Firestore, Functions, Hosting and Emulators. Local work runs through firebase emulators:start; deploys go out with firebase deploy or per service, like firebase deploy --only functions.

The default Firestore rules deny everything: match /{document=**} { allow read, write: if false; }. Add a collection and forget the rules, and every request bounces. Worth checking firestore.rules before your first deploy.

What it helps with

  • add authentication without writing a backend
  • write Firestore security rules that hold up
  • subscribe to collection changes in real time
  • trigger a Cloud Function when a document is created
  • serve a SPA and an API from one domain

Example prompts for the agent

  • show me how to write Firestore rules for the users collection
  • create a Cloud Function that bumps the message counter on a channel
  • set up hosting so /api/** routes to the api function

How to install firebase-app-platform

1Skills CLI (Vercel)

npx skills add BagelHole/DevOps-Security-Agent-Skills --skill firebase-app-platform -a claude-code

2Manually: put the files in place

~/.claude/skills/firebase-app-platform/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/firebase-app-platform/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about firebase-app-platform

How do I install firebase-app-platform in Claude?

Run npx skills add BagelHole/DevOps-Security-Agent-Skills --skill firebase-app-platform -a claude-code. The skill file then lands at ~/.claude/skills/firebase-app-platform/SKILL.md.

What does firebase-app-platform do?

It gives the agent examples and rules for building on Firebase: Auth, Firestore, Cloud Functions and Hosting. That includes data operations, security rules and deploy configs.

What do I need before using it?

Node.js 18+, the Firebase CLI and a Google Cloud account with a Firebase project. Without a project, firebase init and deploys will not go through.

Source text

SKILL.md · MIT
---
name: firebase-app-platform
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.
license: MIT
metadata:
  author: devops-skills
  version: "1.0"
---

# Firebase App Platform

Ship mobile and web backends with Firebase managed services.

## 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

```bash
# Install and authenticate
npm install -g firebase-tools
firebase login

# Initialize in your project directory
firebase init
# Select: Firestore, Functions, Hosting, Emulators

# Start local emulators
firebase emulators:start

# Deploy everything
firebase deploy

# Deploy specific services
firebase deploy --only functions
firebase deploy --only hosting
firebase deploy --only firestore:rules
```

## Firestore Database

### 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 |

## Related Skills

- [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

© devops-skills · MIT · BagelHole/DevOps-Security-Agent-Skills

Similar skills

All skills for Backend and APIs →

From the same set129

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor