Skip to content

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:

  1. Firebase v2 authors using firebase-functions/v2/*
  2. Standalone authors using @google-cloud/functions-framework

Keep the compatibility matrix open as the precise support reference.

These imports stay unchanged for the covered surface:

Firebase v2:

  • firebase-functions/v2
  • firebase-functions/v2/firestore
  • firebase-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

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.ts

Standalone Functions Framework package:

my-functions/
package.json
src/
index.ts
.nimbus/
firebase/
targets.json

Standalone 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".

From the project root:

Terminal window
nimbus codegen

Generated outputs land under .nimbus/firebase/: artifact.json, targets.json, bundle.mjs, and bundle.sha256.

For the watched dev loop with app-root auto-detection (nimbus dev walks up from the current directory, bounded by the nearest .git):

Terminal window
nimbus dev

For production-shaped startup, pass the app path explicitly — nimbus start does no walk-up:

Terminal window
nimbus start --app-dir .

In a monorepo where the functions package is not at the root:

Terminal window
nimbus start --app-dir ./packages/functions
SurfacePath 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.

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 Timestamp helpers

Treat broader Admin SDK usage as unsupported rather than assuming parity — unsupported operations fail clearly instead of silently stubbing.

Covered today:

  • Firestore document triggers with the documented first-slice options
  • setGlobalOptions({ retry }) for Firestore document triggers
  • base onRequest(handler) and onRequest({}, handler) overloads
  • base onCall(handler) and onCall({}, handler) overloads

Fail-fast today:

  • unsupported DocumentOptions, HttpsOptions, or CallableOptions fields
  • root onInit()
  • broader setGlobalOptions() fields such as region, memory, serviceAccount, and enforceAppCheck

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.

Terminal window
nimbus deploy --url <server-url> --token <deploy-token>
  1. Confirm your app root is detected by running nimbus codegen.
  2. Add targets.json for standalone Functions Framework targets if needed.
  3. Run nimbus start --app-dir . (or nimbus dev) and verify trigger and HTTP flows locally.
  4. Confirm firebase-admin usage stays inside the covered slice.
  5. Make handler writes idempotent with at-least-once delivery in mind.
  6. Deploy with nimbus deploy.