File-based functions
Drop files into src/functions. Firescope discovers them and generates Firebase-compatible exports.
Firescope is a convention-first framework for Firebase. It handles function exports, admin SDK scope, generated Firebase config, local env loading, emulator wiring, project connection, rules files, and deploy commands.
npx firescope@latest init my-app
import { firestore } from "firescope/functions"
import { data } from "../../db.js"
export default firestore
.document("users/{userId}")
.onCreate(async ({ event, scope }) => {
await data.collection("audit", scope.db).add({
type: "user.created",
userId: event.params.userId,
createdAt: new Date().toISOString(),
})
})
$ npm run dev
OK Built 4 functions into .firescope/functions
OK Firebase emulators started
Firescope keeps Firebase visible. It removes repetitive setup, not the underlying platform.
Drop files into src/functions. Firescope discovers them and generates Firebase-compatible exports.
Define collection models once and get typed collections, docs, and collection groups in TypeScript.
Builds firebase.json, .firebaserc, and the deployable Functions package.
Loads .env, local files, and mode-specific files with clear override behavior.
npm run dev builds your app and starts Firebase emulators with local project wiring.
firescope deploy builds the generated output and hands it to Firebase deploy.
The public API is intentionally thin. You still write Firebase functions, just with a cleaner context and fewer exports to manage.
import { http } from "firescope/functions"
import { data } from "../db.js"
export default http(async ({ scope, res }) => {
const snapshot = await data
.collection("users", scope.db)
.limit(10)
.get()
res.json({
users: snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
})),
})
})
import { defineFirestoreSchema } from "firescope"
export type AppDb = {
users: {
displayName: string
createdAt: string
}
audit: {
type: "user.created"
userId: string
createdAt: string
}
}
export const data = defineFirestoreSchema<AppDb>()
Firescope's CLI owns the boring path: scaffold, build, run locally, connect when ready, and deploy.
firescope init creates config, functions, public files, and a typed db helper.npm run dev uses a demo Firebase project and starts the emulator loop.npm run connect selects a real Firebase project when you are ready to deploy.Your source app stays organized. Firebase receives a generated Functions package built for deployment.
$ npx firescope build
OK Built 4 functions into .firescope/functions
.firescope/functions/
package.json # Firebase runtime dependencies
src/index.ts # generated exports
lib/index.js # bundled app and Firescope helpers
firebase.json # functions, hosting, emulators
firestore.rules # safe generated default when missing
storage.rules # safe generated default when missing
.firebaserc # selected project
Start with one command, keep Firebase's APIs, and let Firescope handle the framework-shaped glue.