Self-hosting Supabase Edge Functions at scale – clarifying architecture & supported patterns
We are self-hosting Supabase and using Edge Functions heavily in production. We want to confirm our understanding of Edge Functions behavior in Supabase Cloud vs self-hosted, and what patterns are officially supported.
Context:
Supabase is fully self-hosted with Docker. Edge Functions live under supabase/functions, are mounted into the edge-runtime container, and each function uses serve(). Kong routes /functions/v1/* to the edge runtime. We run many functions.
Issue:
serve() works when each function is an isolated entrypoint. Problems occur when trying a central main/index.ts, importing multiple functions, or adding shared middleware. Multiple files calling serve() cause port conflicts and runtime crashes, which is expected if serve() binds to a port.
Our understanding (please correct if wrong):
In Supabase Cloud, serve() does not bind to a port per function and instead registers a handler inside a single server with internal routing and isolate-per-function execution. In self-hosted setups, this routing layer is not exposed, serve() binds to a real port, and multiple serve() calls conflict, forcing isolated entrypoints.
Questions:
Is this Cloud vs self-hosted understanding correct?
Is there an officially supported way for self-hosted setups to use a single router, single port, and shared middleware?
Is moving away from serve() expected for advanced self-hosted use cases?
We want to ensure we are not misunderstanding the architecture or missing a supported pattern.
Context:
Supabase is fully self-hosted with Docker. Edge Functions live under supabase/functions, are mounted into the edge-runtime container, and each function uses serve(). Kong routes /functions/v1/* to the edge runtime. We run many functions.
Issue:
serve() works when each function is an isolated entrypoint. Problems occur when trying a central main/index.ts, importing multiple functions, or adding shared middleware. Multiple files calling serve() cause port conflicts and runtime crashes, which is expected if serve() binds to a port.
Our understanding (please correct if wrong):
In Supabase Cloud, serve() does not bind to a port per function and instead registers a handler inside a single server with internal routing and isolate-per-function execution. In self-hosted setups, this routing layer is not exposed, serve() binds to a real port, and multiple serve() calls conflict, forcing isolated entrypoints.
Questions:
Is this Cloud vs self-hosted understanding correct?
Is there an officially supported way for self-hosted setups to use a single router, single port, and shared middleware?
Is moving away from serve() expected for advanced self-hosted use cases?
We want to ensure we are not misunderstanding the architecture or missing a supported pattern.

self-hosted