Which open-source option replaces Cloud Functions for Firebase
If your server code runs on Cloud Functions for Firebase and you want it inside your own infrastructure, three self-hosted options cover parts of the job: Supabase Edge Functions, Appwrite Functions and PocketBase JavaScript hooks. Which one fits depends mainly on the database you choose and on how large the app is. Cloud Functions requires the pay-as-you-go Blaze plan, so server code is tied to a billing model and a Google-hosted runtime. Firebase Extensions, which many teams use alongside functions, shut down on March 31, 2027, so any extension-backed logic needs a rebuild before that date.
Supabase Edge Functions run on the Deno-based Edge Runtime, which is one of the services in the self-hosted Supabase Docker Compose stack. Operators who take Supabase self-hosting can remove the Edge Runtime from docker-compose.yml if they do not need it. Appwrite Functions run on Open Runtimes, and the sample Docker Compose file includes an Open Runtimes executor, so functions sit inside the same stack as the database, auth and storage. PocketBase hooks are JavaScript code loaded into the single executable through its JavaScript VM plugin, which keeps everything in one process but ties server logic to that one server. Confirm which languages and runtime versions each option supports against its current documentation before you commit.
Plan for triggers as a separate piece of work. Firebase functions often react to Firestore writes or Auth events, and each of these platforms expresses that reaction differently, so the trigger inventory matters more than the runtime choice. Ask the vendor or community for current event hooks, retry behavior and timeout limits for your chosen option, and test the most important trigger in a staging copy. Keep the function list, its triggers and its secrets in version control so the cutover is reviewable.
Mapping Cloud Functions capabilities to open-source options
This table maps each Cloud Functions capability to Supabase Edge Functions, Appwrite Functions and PocketBase JavaScript hooks, and flags where a trigger, scheduler or log feature must be confirmed before you commit. Read the gap rows first, because they decide whether your current triggers can move as-is or need a redesign.
| Capability | Supabase Edge Functions | Appwrite Functions | PocketBase JavaScript hooks |
|---|---|---|---|
| HTTP-triggered functions | Deno-based Edge Runtime serves HTTP endpoints from the self-hosted Docker stack; the Edge Runtime service can be removed if unused | Open Runtimes executor runs HTTP-triggered functions from the sample Docker Compose file | Custom routes and API hooks written in JavaScript run inside the single executable |
| Database change triggers | Not a native Firestore-style trigger; confirm whether Postgres-driven triggers or Realtime listeners fit your event flow | Confirm which database events can invoke a function in your Appwrite version; document-level triggers need testing | Record hooks such as create, update and delete run in the JavaScript VM before or after writes |
| Auth event triggers | Confirm available auth hooks in your Auth (GoTrue) version; many teams call functions from the client after sign-up | Confirm whether user creation or session events can trigger functions in your version | Auth record hooks can run on record events in the auth collection; test each event you rely on |
| Scheduled jobs | Not confirmed in the self-hosting documentation; verify a cron or external scheduler before planning | Confirm scheduling support for functions; many teams run an external scheduler that calls an endpoint | Scheduling is not documented as a built-in feature in the sources reviewed; plan an external cron calling a hook route |
| Secrets and environment variables | Set through the self-hosted environment configuration; the .env secrets must be generated, not left as placeholders | Set as function variables in the Console or API; rotate them through your own process | Store values in environment variables of the host service or a secrets manager you run |
| Logs and execution history | Analytics and logs use optional Logflare and Vector services in the Docker stack | Execution logs are available in the Console; confirm retention in your deployment | Logs go to the process output by default; forward them with your own log pipeline |
| Runtime and deployment model | Functions deploy through the self-hosted stack and its Deno runtime | Functions use Open Runtimes, with language runtimes selected per function | Single Go executable with a JavaScript VM plugin; no separate runtime service |
| Scaling and failure isolation | Scales with the Edge Runtime container; confirm sizing for your load | Executor scaling depends on your Kubernetes or Compose setup; the Helm chart runs single-replica datastores | Runs on one server and scales vertically only, so functions share the same host |
When each open-source function runtime fits
Each of the three open-source options runs server code differently, and that choice shapes how much operational work your team takes on. Read the cards against your current Cloud Functions triggers, your team's language preferences and how much infrastructure you are willing to run yourself.
Supabase Edge Functions
Edge Functions run on the Edge Runtime based on Deno, which is one of the services in the self-hosted Supabase Docker Compose stack. This fits teams already building on Supabase Postgres who want TypeScript functions close to their tables, Auth and Storage. Check the operational load: you run the whole stack yourself, and the self-hosting docs describe the project as community-supported, so confirm your support path before go-live. You can also remove the Edge Runtime from the Compose file if you do not need functions.
Appwrite Functions
Appwrite Functions execute through an Open Runtimes executor that the sample Docker Compose file includes alongside the API, workers and console. This fits teams that want functions tied to Appwrite Auth, Databases and Storage events from one console. Expect more containers to run than a single-service setup, and confirm the runtime versions and languages you need against the current Appwrite release before you migrate. Appwrite's Helm chart docs also state that built-in datastores run a single replica, so plan function workloads around that.
PocketBase JavaScript hooks
PocketBase ships as one executable with a JavaScript VM plugin, so hooks run inside the same process that serves the API and realtime connections. This fits small apps with modest traffic and a single server, where a few event hooks replace simple Cloud Functions triggers. The trade-off is vertical scaling only, and the project states it is pre-1.0 with no guarantee of backward compatibility and no promised support, so pin versions and test every upgrade against your hooks.
Community support and maturity
Supabase self-hosting is community-supported, and PocketBase is developed on a volunteer basis, so neither gives you a vendor response when a function fails in production. Appwrite publishes releases frequently, but you still own patching and incident response for your own install. Before you choose, ask who on your team owns runtime upgrades and what your escalation path is for each option.
Running functions beside Firebase during the transition
Many teams keep Cloud Firestore or Firebase Authentication running while they move server code to a self-hosted platform. This is a reasonable interim state when the data layer is not yet ready to move, but it means the app now calls two backends. The new functions must verify Firebase ID tokens or be fed through a bridge that does, and the remaining Firebase services keep their own security rules, quotas and billing. Confirm which Firebase services stay, who owns each one, and how long the split is expected to last, since a long split doubles the places where access control must be correct.
- Token verification: Confirm that the new endpoints can validate Firebase ID tokens against Google's published keys before any sensitive operation runs.
- Dual access rules: Firestore security rules and the new function's authorization checks must agree, or users will see different data depending on the path.
- Split ownership: Record which team operates the Firebase project and which operates the self-hosted endpoints, along with on-call contacts for each.
- Duplicate writes: If a function writes to both systems during the transition, define which store is authoritative and how conflicts are resolved.
- Exit date: Set a written review date for the split so it does not become permanent by default.
Before cutover, check each new endpoint against the same test cases used for the Cloud Functions it replaces, including failure and retry behavior.
Moving the full backend means Firestore or Realtime Database data, Auth users, Storage files and functions all change platforms, usually in a planned window. Supabase documents migration paths from Firestore and Storage, and Appwrite offers a built-in Firebase migration, but both still require rewriting client SDK calls and checking that the data model survives the move. Because all services change together, client releases, DNS changes and data copies must be sequenced, and rollback depends on keeping the Firebase project readable until the new stack is verified.
- Client release timing: Ship the app build that calls the new endpoints before or with the backend switch, and plan for users on older builds.
- Read-only fallback: Keep the Firebase project intact and readable for a defined period so rollback does not require a re-export.
- Copy and delta: Plan a final incremental copy of data written during the migration window, since a single bulk copy will miss recent changes.
- Scope of the move: Confirm which Firebase features are not carried over, such as Realtime Database or Cloud Functions triggers, and decide how each is replaced.
- Verification: Test authentication, data access and file downloads with real accounts in the new environment before pointing production traffic at it.
The cutover checklist should name an owner for each service and a go or no-go decision point.
Cloud Functions often react to events such as a new Auth user or a Firestore write. When some Firebase services remain, those events still fire in Firebase, but the handler may now live on a self-hosted platform. Pushing events out requires an HTTP endpoint that Firebase can call, a shared secret or signature check, and retry handling that tolerates duplicate deliveries. Teams should also decide whether events are forwarded from Firebase or whether the self-hosted platform polls or subscribes to the data source directly, because each choice has different failure modes.
- Endpoint exposure: A webhook receiver must be reachable from Firebase, which means a public or allowlisted address with TLS in front of it.
- Signature checks: Validate a shared secret or signature on every inbound request and reject unsigned calls.
- Idempotency: Handle repeated deliveries by keying each handler on an event identifier so a retry does not send duplicate emails or double-count records.
- Ordering: Confirm whether out-of-order delivery can affect the handler's logic and whether the handler must read current state instead.
- Failure visibility: Log failed deliveries and alert on them, since a silently dropped trigger can look like a data bug weeks later.
Test each trigger by writing a known record and confirming that the self-hosted handler runs exactly once.
Cloud Functions requires the Blaze plan, the pay-as-you-go tier, so every invocation, build and outbound request is metered in the Firebase project. Running old and new functions side by side can therefore increase the bill during the transition, and the timing of when you stop deploying or invoking Cloud Functions determines how long that overlap costs. Confirm the current pricing for each Firebase product in the project from Google's documentation, since rates and free allowances change, and ask finance how the overlap will be budgeted and approved.
- Overlap cost: Estimate how long old and new functions will both run, and which Firebase charges continue during that period.
- Invocation drivers: Identify which triggers run most often, since high-frequency triggers dominate metered usage.
- Budget alerts: Set billing alerts on the Firebase project so unexpected spikes reach someone before the invoice does.
- Shutdown sequence: Disable triggers first, then remove deployments, so the bill drops as soon as the new path is verified.
- Quote inputs: When requesting a quote for the migration, specify the overlap period, the functions in scope and the Firebase services that remain, so the effort and recurring costs can be compared.
Confirm the final billing date with your Firebase account owner before scheduling the cutover.
Turning off Cloud Functions is the point of no return for server-side behavior, because deployments removed from Firebase cannot be restored from the console without redeployment. Before shutdown, confirm that every client call, trigger and scheduled job has an equivalent on the new platform and that nothing still depends on the old endpoints. Logs and metrics from the final period should be exported and retained according to your records policy, since the Firebase console will not be the place you look during an incident later.
- Inventory: List every function, trigger, scheduled job and HTTP endpoint, and mark the caller for each one.
- Traffic check: Review invocation logs over a representative period to confirm that no client or integration still calls an old endpoint.
- Parity tests: Run the same test cases against old and new handlers and compare outputs, including error responses.
- Log retention: Export logs and configuration needed for audit or investigation before deleting anything.
- Rollback path: Confirm who can redeploy the old functions and how long that takes if the new path fails.
Ask your security and compliance leads to sign off on the inventory and retention plan, and confirm each point against your own environment before disabling anything in production.
Moving functions and triggers off Cloud Functions
This sequence turns each Cloud Functions handler into a documented, tested function on the target runtime, with secrets and triggers accounted for, before clients switch over. No supplied source confirms an automatic export of Cloud Functions code, so each function is rewritten by hand against the new runtime's event model.
Inventory every deployed function and trigger
List each function deployed to the Firebase project, along with its trigger type, region, runtime version, memory setting and the clients or services that call it. Your engineers do this from the Firebase console and the source repository, since deployed code and source are often out of step. The inventory is done when every function has one row, and every row names a trigger type and at least one caller. Anything with no caller goes on a retirement list for confirmation with the product owner.
Classify each function by trigger type
Sort each inventory row into HTTP, database event, authentication event or scheduled job. The classification decides the rewrite: HTTP handlers become endpoints, database and auth triggers become either database hooks or calls made by the new platform, and scheduled jobs need a cron-style mechanism on the target. Flag any function that depends on a trigger without a direct equivalent, such as an event tied to a Firebase product that is not being migrated, for a design decision before coding starts. The output is a classified list reviewed by the team lead.
Map triggers to the target runtime
Choose the target for each class: Supabase Edge Functions on the Deno-based Edge Runtime, Appwrite Functions on Open Runtimes, or PocketBase JavaScript hooks for a small single-server app. Confirm that the target supports each trigger you need, because database events, auth events and scheduled execution do not map one to one across these products. For Supabase, database-driven logic often moves into Postgres triggers or database functions instead of a function, which you should check against the data model migration. Record the mapping in a table that names the source trigger, target mechanism and owner.
Rewrite handlers against the new SDK and data layer
Port each handler's logic from the Firebase Admin SDK to the target's server SDK, replacing Firestore reads and writes with queries against the new database and replacing Firebase Auth checks with the target's session or token verification. Keep business logic in plain modules so it can be unit tested apart from the platform wrapper. Write the handler and its tests in version control and review them as code. The step is complete when each function builds, its unit tests pass and no call to a Firebase SDK remains in the ported code.
Move secrets and environment configuration
Export the values your functions read from Firebase configuration and secret storage, and re-enter them in the target's secret or environment settings. Do not copy secrets into source files or chat threads. Rotate any third-party API keys that were exposed to the old environment, and confirm with each vendor how keys are issued. The output is a checklist, signed off by the security owner, showing each secret name, where it now lives and who can read it.
Redeploy and test against a copy of the Firebase data
Deploy the rewritten functions to a staging environment that holds a copy of the migrated data, not live production records. Run each HTTP endpoint, trigger each database or auth path with test events, and run scheduled jobs manually, comparing results with the outputs of the original functions for the same inputs. Log every mismatch and fix it before retesting. Testing is done when each function has a recorded passing run against the copy and the mismatch log is empty or each open item has an agreed disposition.
Cut over clients and confirm traffic moved
Change the client and service endpoints from the Firebase callable or HTTPS URLs to the new function URLs, and ship updated mobile or web builds where the SDK calls are embedded. Run both paths in parallel for the period your team agrees, and watch logs on both sides for errors and unexpected callers. Cut-over is complete when the old endpoints receive no traffic for an agreed observation window, which you set in advance with the product owner.
Decommission the Cloud Functions deployment
Once traffic has stopped, remove the deployed functions, delete scheduled triggers that still point at the old project, and revoke service account keys the old functions used. Archive the source and the inventory with the migration record so auditors and future engineers can trace what changed. Confirm billing on the Blaze plan reflects the removed functions, and record the decommission date and the person who signed it off.
Questions buyers ask before moving Cloud Functions
What drives the cost of rewriting Cloud Functions for self-hosting?
The cost depends mostly on how many functions exist, how many of them are triggers rather than callable endpoints, and how much they depend on Firebase-specific APIs. The main cost components are the engineering time to rewrite handlers for Supabase Edge Functions, Appwrite Functions or PocketBase hooks, the time to rebuild each trigger as a database or auth hook, testing against the new runtime, and the servers and operations that run the stack afterward. Rewrites are usually one-time, while server capacity, backups and patching recur. Ask any vendor or partner to price the work per function category, and ask what they assume about your Blaze-era dependencies such as Firestore listeners inside functions, scheduled jobs and secrets. Firebase's own pricing for Cloud Functions is usage-based, so compare recurring infrastructure against the Blaze bill you actually receive.
How long does moving Cloud Functions take, and what sets the timeline?
No duration is fixed by the platforms themselves, so treat any number as something to confirm in a written scope. The timeline is set by the inventory of functions, the number of triggers, the depth of Firestore and Auth coupling, the amount of third-party API code, and how many environments need to be cut over. A small set of HTTP endpoints moves far faster than a set of Firestore write triggers that must keep data consistent. Parallel running and cutover testing add time, as does any regulatory review of where functions execute. Ask for a phased plan: inventory, rewrite of one representative function per pattern, staging validation, then production cutover with a rollback path.
Can our team move the functions without outside help?
A team with working experience in TypeScript or JavaScript, Docker and Postgres or SQLite can often move simple functions alone, but the risky parts are trigger semantics, auth hooks and production operations. Before deciding, count the people who already run containers, reverse proxies and database backups, and whether anyone has tested restores. Supabase's self-hosting documentation says self-hosted Supabase is community-supported through GitHub Discussions, GitHub Issues, Discord and Reddit, and enterprises are directed to contact Supabase's Growth Team. Appwrite and PocketBase have their own support channels, which you should confirm for your plan. DeployOpen plans, implements and supports self-hosted platforms in your own infrastructure under fixed-scope engagements, with ongoing support available as a retainer, so an outside partner can cover the parts your team does not want to own.
Can Supabase Edge Functions replace Firestore triggers?
Not directly. Supabase Edge Functions run on the Deno-based Edge Runtime and are invoked over HTTP, so they do not fire on Firestore writes. Firestore's document triggers have no one-to-one equivalent. The usual pattern is to move the data to Postgres tables first, then use database triggers or webhooks that call an Edge Function, or to have the client call the function explicitly. Each approach changes ordering guarantees and retry behavior, so test them with realistic write bursts. Check the Edge Functions and database webhook documentation for the exact behavior of your Supabase version, because the self-hosted Docker configuration pins its own service versions.
How do Firebase Auth triggers translate to self-hosted platforms?
Firebase Auth triggers such as user creation or deletion handlers do not carry over as-is. On Supabase, the closest pattern is a Postgres trigger on the auth.users table or a webhook from Auth, which you must confirm against the Supabase Auth version you deploy. On Appwrite, account events are handled through its Functions and event model, which you should verify for your release. On PocketBase, record and auth hooks written in JavaScript cover login and record events inside the single executable. The migration itself is separate from triggers: Firebase password hashes use a modified scrypt, and the Firebase CLI exports them with their parameters, so ask whether users can be imported without forced resets. Re-run each trigger in staging with imported test accounts before cutover.
What does running self-hosted functions require day to day?
Self-hosting moves responsibility for uptime, scaling, patching, logs, secrets and backups into your own infrastructure. Supabase's Docker guide lists minimum requirements of 4 GB RAM, 2 CPU cores and a 40 GB SSD, and its changelog for the self-hosted configuration reached 0.8.3 on October 16, 2026, with security fixes for Storage and Realtime. Appwrite's installation guide requires 2 CPU cores, 4 GB of RAM, 2 GB of swap and Docker Compose version 2, and its sample Compose file includes an Open Runtimes executor for functions. Its Helm chart documentation notes that built-in datastores run a single replica without failover, so production data should use managed services or operators. Plan for regular upgrades, function runtime patches, tested backups and monitoring, and confirm which of these your chosen platform supports in your environment.
What your team must run once functions leave Google
Moving server code off Cloud Functions means your team owns the runtime that Google currently operates for you. With self-hosted Supabase, that means the Docker Compose stack in which the Edge Runtime on Deno runs beside Auth, PostgREST, Realtime, Storage and the connection pooler. Each of these services has its own upgrade path, and the Docker configuration pins specific upstream versions that you pull and recreate yourselves. Before cutover, assign one owner for the host, one for the Compose or Helm release, and one for the on-call rotation that reads container logs. Confirm with Supabase how it handles security fixes between configuration releases, since its changelog has flagged security fixes and one-way Storage database migrations that require a backup first.
Appwrite moves the functions executor into the stack as an Open Runtimes component, so your patching scope grows with it. The sample Docker Compose file runs PostgreSQL, Redis, Traefik, ClickHouse, workers and the executor, and the Helm chart runs the built-in PostgreSQL, Redis, ClickHouse and object storage as a single replica without failover. Treat that as a hard constraint: production deployments should move those datastores to managed services or operators before functions carry real traffic. Ask your team to confirm which runtimes and versions your chosen Open Runtimes images support, and how long each one receives patches.
Support expectations change as well. Supabase's self-hosting documentation describes self-hosted Supabase as community-supported, with enterprises directed to its Growth Team for commercial arrangements. PocketBase has no official Docker image, and its FAQ says it is developed on a volunteer basis with no promises of maintenance beyond what is available. If an incident lands on a Sunday, your team, or a partner you contract for operations, must be able to diagnose it without vendor tickets. Ask for written runbooks, log retention settings, and a tested rollback procedure for each function deployment before you decommission the Firebase project.
Risks to test before cutover
Moving server code off Cloud Functions changes more than the runtime. Each card below is a test to run in a staging copy of your project before you point production traffic at the new platform. The four areas are trigger behavior, startup and timeout limits, secret handling and release churn, and they interact, so a fix in one often changes another.
Trigger semantics that differ
Firebase triggers fire on Firestore writes, Auth events and Storage changes, and your handlers may assume their ordering and retry behavior. Supabase Edge Functions and Appwrite Functions are invoked through HTTP or the platform's event hooks, so a database event does not always map one to one onto a function call. Write a test that creates, updates and deletes the same record twice and confirm that your handler runs once per intended change and that duplicate deliveries are idempotent. Confirm how each platform retries a failed invocation before you rely on it for billing or notifications.
Cold start and timeout limits
Each function runtime has its own startup cost and execution time ceiling, and both differ from Cloud Functions. Measure the first request after an idle period, then measure a job that runs close to the longest task your app performs, such as a batch write or an image transform. Record the limits your chosen platform reports in its configuration and confirm them in your own environment, because the limits you configure on a self-hosted stack are the ones you actually run with. Document any job that must move to a queue or a scheduled worker instead.
Secret and key handling
Cloud Functions reads secrets from its own configuration store, while self-hosted stacks read them from environment files and container settings you manage. Supabase's self-hosting guide warns against starting with the placeholder values in its example environment file and provides scripts that generate secrets and a JWT key pair. Test that no function ships with a service role key in client code, that rotating the JWT secret invalidates old tokens as expected, and that Studio and the Console are protected by a password you set rather than a default.
Version churn in fast releases
Self-hosted function runtimes change quickly, and an upgrade can alter how your code is packaged or invoked. Appwrite shipped 2.0 on September 4, 2026 and 2.5.0 on October 13, 2026, and the self-hosted Supabase Docker configuration reached 0.8.3 on October 16, 2026. Before cutover, pin the image versions you test, read each changelog for function and Edge Runtime changes, and rehearse the upgrade path on a copy. Note that the Supabase changelog flags one-way Storage database migrations that need a backup first.
How DeployOpen scopes and delivers a function migration
DeployOpen plans, implements, integrates, hardens, documents and supports self-hosted open-source platforms inside your own cloud accounts, data centers or air-gapped networks. For a move off Cloud Functions, that means mapping each function and trigger to a runtime you choose, then delivering it with tests, documentation and a handover your team can run.
How we scope
- Inventory every Cloud Functions trigger, scheduled job and HTTP endpoint, noting which ones depend on Firestore or Auth events.
- Decide per function whether it moves to Supabase Edge Functions, Appwrite Functions or PocketBase JavaScript hooks.
- Agree the written scope, deliverables and timeline before work starts, since most engagements are fixed-scope.
How we build
- Rebuild each function on the chosen runtime, with secrets moved into configuration and not hard-coded in source.
- Replace database and auth triggers with equivalents the target platform actually supports, and record every gap.
- Test each function against the same inputs used in production, including failure and retry paths, before cutover.
How we hand over
- Document each function's trigger, dependencies, configuration keys and rollback steps in a handover pack.
- Walk your engineers through deploying, updating and monitoring the functions on your own infrastructure.
- Confirm with you which runtime and platform versions your team will pin and how upgrades will be tested.
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer after handover.
- Upgrades to the function runtime and platform are tested before they reach production.
- Ask us to confirm the support scope and response terms in the written agreement before you sign.

