Initialize new Firebase project with proven architecture. Guides through firebase init, choosing hosting/auth/functions patterns, emulator configuration, and initial project structure setup.
/plugin marketplace add 2389-research/claude-plugins/plugin install firebase-development@2389-research-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
This sub-skill guides you through initializing a new Firebase project with proven architecture patterns. It handles:
firebase initThe workflow uses TodoWrite to track 12-14 steps from initialization to first emulator run.
Use this sub-skill when:
Do not use for:
All patterns are documented in the main @firebase-development skill. This sub-skill helps you choose and implement those patterns for a new project.
Key Decisions Made:
These decisions shape your project structure and are made via AskUserQuestion prompts.
This sub-skill creates a TodoWrite checklist with 12-14 steps. Follow the checklist to systematically set up your Firebase project.
Actions:
# Check if Firebase CLI is installed
firebase --version
# If not installed, install via npm
npm install -g firebase-tools
# Login to Firebase (opens browser)
firebase login
Expected: Version output (e.g., 13.0.0 or higher)
Actions:
# Create project directory
mkdir my-firebase-project
cd my-firebase-project
# Initialize git
git init
git branch -m main
# Create .gitignore
cat << 'EOF' > .gitignore
node_modules/
.env
.env.local
.firebase/
lib/
dist/
*.log
.DS_Store
EOF
Expected: Clean directory ready for Firebase initialization
Actions:
firebase init
Interactive Prompts:
Select features: (use spacebar to select, enter to confirm)
Select project:
Firestore rules:
firestore.rulesFirestore indexes:
firestore.indexes.jsonFunctions language:
ESLint:
Install dependencies:
Hosting:
public (we'll reconfigure later)Single-page app:
Emulators:
Emulator ports:
Download emulators:
Expected: Firebase project initialized with TypeScript functions
Use AskUserQuestion to gather decisions:
Question 1: Hosting Configuration
Question: "What hosting configuration do you need?"
Header: "Hosting"
Options:
- "Single Site" (One hosting site, simple project)
- "Multiple Sites" (Multiple independent URLs with site: config)
- "Multiple with Builds" (Multiple sites with predeploy hooks using target:)
- "Not Sure" (Get recommendations based on project type)
Question 2: Authentication Approach
Question: "What authentication method will you use?"
Header: "Auth"
Options:
- "API Keys" (MCP tools, server-to-server, programmatic access)
- "Firebase Auth" (User-facing app with login UI)
- "Both" (Firebase Auth for web + API keys for tools)
- "None Yet" (Skip for now, add later)
Question 3: Functions Architecture
Question: "What Cloud Functions architecture fits your project?"
Header: "Functions"
Options:
- "Express API" (Many related endpoints, need middleware, RESTful routing)
- "Domain Grouped" (Feature-rich app with distinct areas: posts, admin, etc.)
- "Individual Files" (Independent functions, maximum modularity)
- "Not Sure" (Get recommendations)
Question 4: Security Model
Question: "What security model do you prefer?"
Header: "Security"
Options:
- "Server-Write-Only" (Preferred: Cloud Functions handle all writes, maximum security)
- "Client-Write" (High-volume writes, need fastest UX, more complex rules)
- "Mixed" (Some collections server-write, others client-write)
- "Not Sure" (Recommend server-write-only for most projects)
Store responses for use in subsequent steps.
Actions:
Based on hosting decision from Step 4, update firebase.json:
For Single Site:
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"functions": [
{
"source": "functions",
"codebase": "default",
"ignore": [
"node_modules",
".git",
"firebase-debug.log",
"firebase-debug.*.log"
],
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
]
}
],
"hosting": {
"source": "hosting",
"frameworksBackend": {
"region": "us-central1"
}
},
"emulators": {
"auth": { "port": 9099 },
"functions": { "port": 5001 },
"firestore": { "port": 8080 },
"hosting": { "port": 5000 },
"ui": { "enabled": true, "port": 4000 },
"singleProjectMode": true
}
}
For Multiple Sites (site: based):
{
"hosting": [
{
"site": "myproject-main",
"source": "hosting",
"frameworksBackend": {"region": "us-central1"}
},
{
"site": "myproject-api",
"public": "hosting-api",
"rewrites": [{"source": "/**", "function": "api"}]
}
],
"emulators": {
"auth": { "port": 9099 },
"functions": { "port": 5001 },
"firestore": { "port": 8080 },
"hosting": { "port": 5000 },
"ui": { "enabled": true, "port": 4000 },
"singleProjectMode": true
}
}
Note: Always include singleProjectMode: true and ui.enabled: true in emulators config.
Reference main skill for full hosting patterns: @firebase-development → Multi-Hosting Setup
Actions:
Navigate to functions directory and configure:
cd functions
# Install additional dependencies based on architecture choice
# For Express architecture:
npm install express cors
npm install --save-dev @types/express @types/cors
# For all projects:
npm install firebase-admin firebase-functions
# Install dev tools
npm install --save-dev vitest @vitest/ui biome typescript
Create functions/src/ structure based on architecture from Step 4:
For Express API:
cd src
mkdir middleware tools services shared
touch middleware/.gitkeep tools/.gitkeep services/.gitkeep shared/types.ts
For Domain-Grouped:
cd src
mkdir shared
mkdir shared/types shared/validators shared/utils
touch shared/types/index.ts
For Individual Files:
cd src
mkdir functions
touch functions/.gitkeep
Update functions/package.json scripts:
{
"scripts": {
"build": "tsc",
"build:watch": "tsc --watch",
"serve": "npm run build && firebase emulators:start --only functions",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log",
"test": "vitest run",
"test:watch": "vitest",
"test:emulator": "vitest run --config vitest.emulator.config.ts",
"lint": "biome check .",
"lint:fix": "biome check --write ."
}
}
Actions:
Create functions/src/index.ts based on architecture choice:
For Express API:
// ABOUTME: Main entry point for Firebase Functions - exports API endpoint with routing
// ABOUTME: Configures Express app with CORS and health check
import * as admin from 'firebase-admin';
import { onRequest } from 'firebase-functions/v2/https';
import express, { Request, Response } from 'express';
import cors from 'cors';
admin.initializeApp();
const app = express();
app.use(cors({ origin: true }));
app.use(express.json());
app.get('/health', (_req: Request, res: Response) => {
res.status(200).json({ status: 'ok', timestamp: new Date().toISOString() });
});
// Add your routes here
export const api = onRequest({ invoker: 'public', cors: true }, app);
For Domain-Grouped:
// ABOUTME: Main entry point - re-exports all Cloud Functions
// ABOUTME: Organizes functions by domain for clear structure
// Export functions from domain files as you create them
// Example:
// export * from './posts';
// export * from './users';
For Individual Files:
// ABOUTME: Main entry point - exports all Cloud Functions
// ABOUTME: Imports and re-exports individual function files
import { onRequest } from 'firebase-functions/v2/https';
export const helloWorld = onRequest((req, res) => {
res.json({ message: 'Hello from Firebase!' });
});
// Import and export additional functions as you create them
If using API keys (from Step 4), create middleware:
mkdir -p functions/src/middleware
Create functions/src/middleware/apiKeyGuard.ts:
// ABOUTME: API key authentication middleware for Express routes
// ABOUTME: Validates API keys from x-api-key header against Firestore collection
import { Request, Response, NextFunction } from 'express';
import * as admin from 'firebase-admin';
// Extend Express Request type
declare global {
namespace Express {
interface Request {
userId?: string;
}
}
}
export async function apiKeyGuard(req: Request, res: Response, next: NextFunction) {
const apiKey = req.headers['x-api-key'] as string;
// Replace 'myproj_' with your project prefix
if (!apiKey || !apiKey.startsWith('myproj_')) {
res.status(401).json({ error: 'Invalid API key' });
return;
}
const db = admin.firestore();
const apiKeysQuery = await db
.collectionGroup('apiKeys')
.where('keyId', '==', apiKey)
.where('active', '==', true)
.limit(1)
.get();
if (apiKeysQuery.empty) {
res.status(401).json({ error: 'Invalid API key' });
return;
}
req.userId = apiKeysQuery.docs[0].data().userId;
next();
}
Reference main skill for full patterns: @firebase-development → Cloud Functions Architecture, Authentication
Actions:
Update firestore.rules based on security model from Step 4:
For Server-Write-Only (Recommended):
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Helper functions
function isAuthenticated() {
return request.auth != null;
}
function isOwner(userId) {
return isAuthenticated() && request.auth.uid == userId;
}
// Config collection (public read, server write)
match /config/{configId} {
allow read: if true;
allow write: if false; // Only Cloud Functions can write
}
// Users collection
match /users/{userId} {
allow read: if isOwner(userId);
allow write: if false; // Only Cloud Functions can write
// API keys subcollection (if using API keys)
match /apiKeys/{keyId} {
allow read: if isOwner(userId);
allow write: if false; // Only Cloud Functions can write
}
}
// Default deny
match /{document=**} {
allow read, write: if false;
}
}
}
For Client-Write with Validation:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Helper functions
function isAuthenticated() {
return request.auth != null;
}
function isOwner(userId) {
return isAuthenticated() && request.auth.uid == userId;
}
function isAdmin() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}
// Users collection
match /users/{userId} {
allow read: if isOwner(userId) || isAdmin();
allow create: if isAuthenticated() && request.auth.uid == userId;
allow update: if isOwner(userId) &&
request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['displayName', 'bio', 'photoURL', 'updatedAt']);
allow delete: if false; // Never allow user deletion via client
}
// Add collection rules as needed
// Default deny
match /{document=**} {
allow read, write: if false;
}
}
}
Add collection group rules if using API keys:
// Add after other rules, before default deny
match /{path=**}/apiKeys/{keyId} {
allow read: if request.auth != null;
}
Reference main skill for patterns: @firebase-development → Security Model, Firestore Rules Patterns
Actions:
Create functions/vitest.config.ts:
// ABOUTME: Vitest configuration for Firebase Cloud Functions testing
// ABOUTME: Configures Node.js test environment with TypeScript support and coverage settings
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
globals: true,
include: ['**/__tests__/**/*.test.ts', '**/*.test.ts'],
exclude: ['**/node_modules/**', '**/lib/**', '**/__tests__/emulator/**'],
coverage: {
provider: 'v8',
reporter: ['text', 'lcov', 'html'],
thresholds: {
branches: 50,
functions: 60,
lines: 60,
statements: 60,
},
},
clearMocks: true,
restoreMocks: true,
},
});
Create functions/vitest.emulator.config.ts:
// ABOUTME: Vitest configuration specifically for emulator tests
// ABOUTME: Used when running tests that require Firebase emulators
import { defineConfig, mergeConfig } from 'vitest/config';
import baseConfig from './vitest.config';
export default mergeConfig(
baseConfig,
defineConfig({
test: {
include: ['**/__tests__/emulator/**/*.test.ts'],
exclude: ['**/node_modules/**', '**/lib/**'],
testTimeout: 30000, // Longer timeout for emulator tests
},
})
);
Create test directory structure:
cd functions/src
mkdir -p __tests__/emulator
Create example unit test functions/src/__tests__/health.test.ts:
import { describe, it, expect } from 'vitest';
describe('Health Check', () => {
it('should return ok status', () => {
const result = { status: 'ok' };
expect(result.status).toBe('ok');
});
});
Reference main skill: @firebase-development → Modern Tooling Standards → Testing with vitest
Actions:
Create functions/biome.json:
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": false,
"ignore": ["node_modules", "lib", "dist", "**/*.log"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "single"
}
}
}
Run initial lint:
cd functions
npm run lint:fix
Expected: All files formatted according to biome config
Actions:
Create functions/.env.example:
# Firebase Project Configuration
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_REGION=us-central1
# API Keys (if using custom API keys)
API_KEY_PREFIX=myproj_
# External Services (add as needed)
# OPENAI_API_KEY=sk-...
# SENDGRID_API_KEY=SG...
Create functions/.env:
# Copy example and fill in actual values
cp functions/.env.example functions/.env
For hosting (if using Next.js/React):
Create hosting/.env.local:
NEXT_PUBLIC_USE_EMULATORS=true
NEXT_PUBLIC_FIREBASE_API_KEY=your-api-key
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456789
NEXT_PUBLIC_FIREBASE_APP_ID=1:123456789:web:abcdef
Important: Never commit .env or .env.local files (already in .gitignore)
Actions:
# Return to project root
cd ..
# Add all files
git add .
# Create initial commit
git commit -m "feat: initial Firebase project setup
- Configure firebase.json with emulators
- Set up TypeScript functions with [architecture choice]
- Add Firestore rules ([security model])
- Configure vitest for testing
- Set up biome for linting
- Add environment variable templates
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>"
Actions:
# Start emulators
firebase emulators:start
Verify in terminal output:
Open Emulator UI:
open http://127.0.0.1:4000
Test health endpoint (if using Express):
curl http://127.0.0.1:5001/[project-id]/us-central1/api/health
Expected: {"status":"ok","timestamp":"..."}
Stop emulators:
Actions:
Create functions/src/__tests__/setup.test.ts:
import { describe, it, expect } from 'vitest';
describe('Project Setup', () => {
it('should have correct Node version', () => {
const nodeVersion = process.version;
const majorVersion = parseInt(nodeVersion.slice(1).split('.')[0]);
expect(majorVersion).toBeGreaterThanOrEqual(18);
});
it('should load environment variables', () => {
// This will pass even without .env in CI
expect(process.env.NODE_ENV).toBeDefined();
});
});
Run tests:
cd functions
npm run test
Expected: All tests pass
Final commit:
git add .
git commit -m "test: add initial test suite
Verifies project setup and environment configuration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>"
Quick reference for running firebase init with different configurations:
firebase init
# Only Firestore
firebase init firestore
# Only Functions
firebase init functions
# Only Hosting
firebase init hosting
# Only Emulators
firebase init emulators
# Multiple features
firebase init firestore functions hosting emulators
# Use existing firebase.json
firebase init --project=your-project-id
# Skip all prompts (only works with existing firebase.json)
firebase init --non-interactive
# List available projects
firebase projects:list
# Use specific project
firebase use your-project-id
# Add project alias
firebase use --add
# Check current project
firebase use
# Deploy everything
firebase deploy
# Deploy specific services
firebase deploy --only firestore
firebase deploy --only functions
firebase deploy --only hosting
# Start emulators
firebase emulators:start
# Export emulator data
firebase emulators:export ./backup
# Import data on start
firebase emulators:start --import=./backup
my-firebase-project/
├── .gitignore
├── firebase.json
├── firestore.rules
├── firestore.indexes.json
├── functions/
│ ├── package.json
│ ├── tsconfig.json
│ ├── biome.json
│ ├── vitest.config.ts
│ ├── .env.example
│ ├── .env
│ └── src/
│ ├── index.ts
│ ├── middleware/
│ │ └── apiKeyGuard.ts
│ ├── tools/
│ │ └── .gitkeep
│ └── __tests__/
│ ├── setup.test.ts
│ └── emulator/
│ └── .gitkeep
└── hosting/
└── index.html
my-firebase-project/
├── .gitignore
├── firebase.json
├── firestore.rules
├── firestore.indexes.json
├── functions/
│ ├── package.json
│ ├── tsconfig.json
│ ├── biome.json
│ ├── vitest.config.ts
│ └── src/
│ ├── index.ts
│ ├── posts.ts
│ ├── users.ts
│ ├── admin.ts
│ ├── shared/
│ │ ├── types/
│ │ ├── validators/
│ │ └── utils/
│ └── __tests__/
│ ├── posts.test.ts
│ └── emulator/
│ └── workflow.test.ts
└── hosting/
└── (Next.js app files)
my-firebase-project/
├── .gitignore
├── firebase.json
├── firestore.rules
├── firestore.indexes.json
├── functions/
│ └── (function files)
├── hosting/ # Main site
│ └── (Next.js app)
├── hosting-api/ # API site
│ └── index.html
└── hosting-admin/ # Admin site
└── index.html
After completing all TodoWrite steps, verify:
firebase init completed successfullycd functions && npm run buildcd functions && npm run testcd functions && npm run lintfirebase emulators:startfirebase deploy --only firestore:rules.env files created and .gitignoredAfter project setup is complete:
All patterns used in this workflow are documented in the main skill:
Creating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems. Create original algorithmic art rather than copying existing artists' work to avoid copyright violations.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Create beautiful visual art in .png and .pdf documents using design philosophy. You should use this skill when the user asks to create a poster, piece of art, design, or other static piece. Create original visual designs, never copying existing artists' work to avoid copyright violations.