Firebase Provider
Setup
Auth uses a service account JSON file from the Firebase console.
- Go to Firebase console → Project settings → Service accounts
- Click Generate new private key → download the JSON file
- Store it somewhere safe (outside version control)
The firebase option in @Deploy is optional - if FIREBASE_SA is set in your environment, it's picked up automatically.
// Explicit
@Deploy({ firebase: process.env.FIREBASE_SA! })
// Or let it read FIREBASE_SA from env
@Deploy({ dryRun: true })
Local Emulator Integration
Puls supports local development using the Firebase Local Emulator Suite (specifically Firebase Auth and Cloud Firestore).
When you configure the standard Firebase emulator environment variables, Puls automatically intercepts API requests, bypasses production service account checks, and routes operations to your local emulators:
# Set emulator hosts in your shell before running Puls
export FIRESTORE_EMULATOR_HOST=localhost:8080
export FIREBASE_AUTH_EMULATOR_HOST=localhost:9099
When these environment variables are active:
1. Token Bypass: Puls does not require a valid FIREBASE_SA service account file and uses mock access credentials.
2. Firestore Rules: Security rules are deployed directly to the local Firestore emulator rules engine.
3. Firestore Indexes & Auth Config: Since the local emulators do not support management REST APIs for indexes and authentication provider setups, Puls automatically intercepts these calls and simulates successful results locally so that stacks deploy and tear down cleanly without errors.
Hosting
Deploy a static site from a local build directory.
Firebase.Hosting("your-site-id")
.source("./dist") // path to your built static files
.domain("example.com") // optional custom domain
The site ID is the Firebase Hosting site name - by default it matches your project ID (e.g. my-project → https://my-project.web.app). You can override the displayed URL using .domain("yourdomain.com").
Deploy flow:
- Creates a new Hosting version
- SHA256-hashes all files in the source directory
- Sends the hash map to Firebase - only files that changed are uploaded
- Finalizes the version and creates a release
- Outputs the live URL
Idempotency: Each deploy creates a new release (Firebase's native model). Previous releases remain in the console but are inactive.
App Check
Declaratively manage App Check attestation enforcement modes for primary backend services.
Supported Services:
| Service Name | API Target |
|---|---|
firestore |
firestore.googleapis.com (Cloud Firestore) |
storage |
firebasestorage.googleapis.com (Cloud Storage) |
database |
firebasedatabase.googleapis.com (Realtime Database) |
auth |
identitytoolkit.googleapis.com (Firebase Authentication) |
On deploy, Puls queries the current enforcement statuses and patches services whose configurations differ. In teardowns (destroy()), Puls automatically reverts all configured services back to "OFF" to leave the environment clean.
Firestore
Deploy Cloud Firestore security rules and configure composite indexes.
Storage
Manage Cloud Storage rules and CORS policies.
Firebase.Storage("my-bucket")
.rules("./storage.rules")
.cors([
{
origin: ["*"],
method: ["GET", "POST", "PUT"],
responseHeader: ["Content-Type"],
maxAgeSeconds: 3600,
},
]);
Auth
Configure Authentication sign-in providers and authorized domains.
Firebase.Auth()
.email(true) // Enable email/password sign-in
.anonymous(true) // Enable anonymous access
.authorizedDomains(["example.com", "my-app.web.app"]);
Remote Config
Declare typed parameters and conditions for Firebase Remote Config templates with ETag-safe PUT operations.
Firebase.RemoteConfig()
.string("welcome_message", "Hello, World!")
.bool("feature_flag_active", true)
.number("max_retries", 3)
.condition("is_android", "device.os == 'android'")
.override("welcome_message", "is_android", "Hello from Android!");
Full example
import "dotenv/config";
import "reflect-metadata";
import { Stack, Deploy } from "@puls-dev/core";
import { Firebase } from "@puls-dev/firebase";
@Deploy({ dryRun: false })
class AppStack extends Stack {
// Static Hosting
site = Firebase.Hosting("my-app-hosting")
.source("./dist")
.domain("myapp.io");
// Backend Security Attestation
appcheck = Firebase.AppCheck()
.enforce("firestore")
.enforce("storage");
// Database Rules
db = Firebase.Firestore()
.rules("./firestore.rules");
// Storage configuration
bucket = Firebase.Storage("my-app-media")
.rules("./storage.rules");
// Authentication configuration
auth = Firebase.Auth()
.email(true)
.authorizedDomains(["myapp.io"]);
}
Build your site first, then deploy:
# Web application build example
npm run build # outputs static assets to ./dist
npx tsx examples/deploy.ts
Service account permissions
The service account needs the Firebase Hosting Admin, App Check Admin, Cloud Datastore Owner, and App Engine Admin roles depending on which features you use.
Ensure these roles are granted via IAM to the service account email in your GCP Console under IAM & Admin → IAM.