Migrate Cloud Functions
Move Firebase Cloud Functions or standalone Functions Framework handlers onto Nimbus today. The goal is unchanged source imports for the covered surface — not a second Nimbus-specific handler API.
Two audiences are covered:
- Firebase v2 authors using
firebase-functions/v2/* - Standalone authors using
@google-cloud/functions-framework
Keep the compatibility matrix open as the precise support reference.
1. Keep your handler modules and imports
Section titled “1. Keep your handler modules and imports”These imports stay unchanged for the covered surface:
Firebase v2:
firebase-functions/v2firebase-functions/v2/firestorefirebase-functions/v2/https- covered
firebase-admin/app - covered
firebase-admin/firestore
Standalone Functions Framework:
@google-cloud/functions-framework- covered
firebase-admin/app - covered
firebase-admin/firestore
2. Check your project layout
Section titled “2. Check your project layout”Firebase project — the conventional layout is preserved, including
firebase.json functions.source and multi-codebase layouts:
my-app/ firebase.json functions/ package.json src/ index.tsStandalone Functions Framework package:
my-functions/ package.json src/ index.ts .nimbus/ firebase/ targets.jsonStandalone packages require a hand-authored
.nimbus/firebase/targets.json, because functions.cloudEvent() and
functions.http() name targets without carrying their Firestore or HTTP
binding metadata in source:
{ "version": 1, "targets": [ { "name": "helloWorld", "entrypoint": "registry.helloWorld", "authoring_surface": "functions_framework", "signature_type": "http", "binding": { "binding_kind": "https", "exposure": "http", "path": "/hello", "execution": "request_principal" } }, { "name": "syncUser", "entrypoint": "registry.syncUser", "authoring_surface": "functions_framework", "signature_type": "cloud_event", "binding": { "binding_kind": "firestore_document", "event_type": "google.cloud.firestore.document.v1.written", "database": "(default)", "document": "users/{userId}", "execution": "service_account" } } ]}Firestore document bindings must use "execution": "service_account".
3. Generate artifacts
Section titled “3. Generate artifacts”From the project root:
nimbus codegenGenerated outputs land under .nimbus/firebase/: artifact.json,
targets.json, bundle.mjs, and bundle.sha256.
4. Run locally
Section titled “4. Run locally”For the watched dev loop with app-root auto-detection (nimbus dev walks
up from the current directory, bounded by the nearest .git):
nimbus devFor production-shaped startup, pass the app path explicitly — nimbus start does no walk-up:
nimbus start --app-dir .In a monorepo where the functions package is not at the root:
nimbus start --app-dir ./packages/functions5. Know the HTTP path rules
Section titled “5. Know the HTTP path rules”| Surface | Path rule |
|---|---|
functions.http(name, handler) | Comes from targets.json |
Firebase onRequest | /<exportName> |
Firebase onCall | /<exportName> |
For example, export const hello = onRequest(...) is served at /hello on
the main server port.
6. Write for at-least-once delivery
Section titled “6. Write for at-least-once delivery”Firestore triggers on Nimbus use durable at-least-once delivery, journal-backed crash/restart replay, bounded retry, service-principal execution, and chain-depth limiting. Practically:
- make handler code idempotent
- expect follow-up writes to be retried
- expect recursive trigger chains to be intentionally bounded
7. Stay inside the covered firebase-admin slice
Section titled “7. Stay inside the covered firebase-admin slice”The covered admin surface for handler bodies is:
initializeApp(),getApp(),getApps(),deleteApp()getFirestore()collection(path),doc(path)get(),set(),update(),delete()DocumentSnapshot.data(),get(fieldPath)- covered
Timestamphelpers
Treat broader Admin SDK usage as unsupported rather than assuming parity — unsupported operations fail clearly instead of silently stubbing.
8. Respect the option boundaries
Section titled “8. Respect the option boundaries”Covered today:
- Firestore document triggers with the documented first-slice options
setGlobalOptions({ retry })for Firestore document triggers- base
onRequest(handler)andonRequest({}, handler)overloads - base
onCall(handler)andonCall({}, handler)overloads
Fail-fast today:
- unsupported
DocumentOptions,HttpsOptions, orCallableOptionsfields - root
onInit() - broader
setGlobalOptions()fields such asregion,memory,serviceAccount, andenforceAppCheck
The covered callable slice includes the Firebase callable JSON envelope,
default CORS behavior, HttpsError / FunctionsErrorCode mapping, and the
unauthenticated baseline. App Check verification is deferred.
9. Deploy
Section titled “9. Deploy”nimbus deploy --url <server-url> --token <deploy-token>Suggested order
Section titled “Suggested order”- Confirm your app root is detected by running
nimbus codegen. - Add
targets.jsonfor standalone Functions Framework targets if needed. - Run
nimbus start --app-dir .(ornimbus dev) and verify trigger and HTTP flows locally. - Confirm
firebase-adminusage stays inside the covered slice. - Make handler writes idempotent with at-least-once delivery in mind.
- Deploy with
nimbus deploy.