Supabase Edge Functions en la práctica: runtime Deno y despliegue global en el borde

Mirando el panel de monitorización, esa línea roja no mentía: el tiempo de respuesta de la API había saltado a 2,3 segundos.
El usuario estaba en Japón y el servidor en Ohio. Solo el viaje de ida y vuelta ya sumaba 120 ms, más la consulta a la base de datos y la lógica de negocio. ¿Cómo no iba a ir lento?
«¿Y si probamos edge functions?», escribió un compañero en Slack.
Lo miré con recelo. ¿Edge functions? ¿No es solo ejecutar código en otro sitio? ¿Qué diferencia puede haber? Lo probé y me quedé helado: arranque en frío de 120 ms, respuesta en 47 ms. La misma lógica, movida del nodo de Ohio al de Tokio, casi 5 veces más rápida.
Supabase Edge Functions usa el runtime Deno y ejecuta código en nodos edge de todo el mundo. En este artículo verás por qué es tan rápido, en qué se diferencia Deno de Node.js, cómo montar una Edge Function desde cero y cómo elegir frente a Cloudflare Workers.
1. Conceptos clave: qué son las Edge Functions y por qué son rápidas
En pocas palabras, Edge Functions mueven tu código del «servidor central» al «nodo edge».
Antes, si desplegabas una función Lambda, corría en un servidor de una región fija (por ejemplo, este de EE. UU. o Europa). Un usuario en Tokio enviaba la petición, los datos cruzaban el océano hasta el este, se procesaban y volvían. La distancia física marca un suelo de latencia: la luz tampoco es infinita.
Edge Functions cambia el enfoque. Tu código se empaqueta en un formato compacto llamado ESZip y se distribuye automáticamente a decenas de nodos edge en todo el mundo. Si el usuario pide desde Tokio, el código se ejecuta en el nodo edge de Tokio y se elimina la parte del viaje transoceánico.
¿Qué es ESZip?
Es un formato de empaquetado del equipo de Deno. A diferencia de un bundle JavaScript tradicional, ESZip empaqueta el código y todo el grafo de dependencias de módulos. ¿La ventaja? Al arrancar no hace falta ir a la red a buscar dependencias: todo está en un solo archivo. El arranque en frío pasa de «descargar paquetes + resolver + ejecutar» a «descomprimir + ejecutar».
Modelo de ejecución con Isolate
Supabase Edge Functions corre dentro de un V8 Isolate, no en un contenedor o máquina virtual tradicional. ¿Qué es un Isolate? Piensa en un contenedor Worker ultraligero. Un proceso puede ejecutar decenas de Isolates, cada uno atiende una petición. Más ligero que un contenedor y arranca más rápido.
Según la documentación oficial de Supabase, el límite de tiempo de CPU del Isolate es 400 s (límite blando + límite duro). Suena a mucho, pero las edge functions no están para trabajo pesado: validar JWT, reenviar peticiones, lógica ligera. El cómputo intensivo mejor dejarlo en el servidor central.
Mira el ejemplo más simple de una Edge Function:
// Ejemplo mínimo de Edge Function
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
Deno.serve(async (req) => {
const { name } = await req.json()
const data = { message: `Hello ${name}!` }
return new Response(JSON.stringify(data), {
headers: { "Content-Type": "application/json" }
})
})
Este código corre en un nodo edge. Llega la petición del usuario, Deno.serve la recibe, se procesa y se devuelve la respuesta. Todo ocurre en el nodo más cercano al usuario.
2. Runtime Deno: la «evolución segura» de Node.js
La primera vez que oí hablar de Deno me pregunté: Node.js ya es tan maduro, ¿para qué otro runtime?
La respuesta es sencilla: Node.js se diseñó demasiado pronto y muchos problemas salieron después.
Diferencias de seguridad
La política por defecto de Node.js es «confiar en todo». ¿Tu código quiere leer el sistema de archivos? Sin problema. ¿Conectarse a la red? Adelante. ¿Ejecutar comandos del sistema? También. Un dependencia maliciosa puede hacer de todo.
Deno invierte el enfoque. Por defecto tu código vive en un «sandbox»: no lee archivos, no se conecta a la red, no ejecuta comandos del sistema. ¿Necesitas permisos? Hay que declararlos explícitamente. Por ejemplo:
# Permiso de red
deno run --allow-net server.ts
# Permiso de lectura y escritura de archivos
deno run --allow-read --allow-write file_ops.ts
# Todos los permisos (usar con cuidado)
deno run -A everything.ts
Este diseño importa mucho en entornos edge. Tu función corre en decenas de nodos repartidos por el mundo; si la atacan, el impacto se multiplica.
Diferencias en el arranque en frío
Son datos medidos. Ejecuté el mismo código en Deno Deploy y en AWS Lambda:
| Runtime | Tiempo de arranque en frío |
|---|---|
| Deno Deploy | ~120 ms |
| AWS Lambda (Node.js) | 300-500 ms |
Tres veces de diferencia. Las causas son varias, pero el núcleo es que Deno no arrastra el legado de Node.js: carga CommonJS, resolución de require, búsqueda en node_modules. ESZip más TypeScript nativo eliminan gran parte del coste de arranque.
Cambio en el sistema de módulos
Node.js usa CommonJS: require() para cargar módulos, npm, package.json, directorio node_modules. En proyectos grandes, ese directorio puede pesar cientos de megabytes.
Deno usa el estándar ESM directamente. Sin npm, sin package.json, sin node_modules. Los imports son URLs:
// Importar directamente desde URL
import { serve } from "https://deno.land/[email protected]/http/server.ts"
// O usar JSR (repositorio de paquetes de Deno)
import { cors } from "jsr:@hono/hono/cors"
En la primera ejecución, Deno descarga y cachea los módulos. En los arranques siguientes lee la caché local sin volver a la red.
TypeScript sin configuración
En Node.js para TypeScript necesitas ts-node o configurar webpack/vite/esbuild y un tsconfig.json. Deno no. Soporta TypeScript de forma nativa y ejecuta archivos .ts directamente:
deno run hello.ts
Compilación y comprobación de tipos ocurren en runtime. La experiencia de desarrollo queda mucho más limpia.
El tema del vendor lock-in
También me preocupaba: ¿usar Supabase Edge Functions me ata a su plataforma?
No necesariamente. Deno es un runtime open source y el Edge Runtime de Supabase también lo es (código en GitHub). En teoría puedes ejecutar Edge Runtime en tus propios servidores. Claro, el coste de operar una red edge global corre por tu cuenta. Pero a nivel técnico no estás «atrapado».
3. Práctica: monta tu primera Edge Function en 10 minutos
No te quedes solo en la teoría: pruébalo en las manos.
Seguí la documentación oficial de principio a fin: de la instalación al despliegue en menos de 10 minutos. Este es el flujo completo:
Paso 1: instalar Supabase CLI
npm install -g supabase
Después puedes comprobar la versión:
supabase --version
# Salida similar: 1.200.0
Paso 2: inicializar el proyecto
Si ya tienes un proyecto Supabase, inicializa en su directorio:
supabase init
Esto crea un directorio supabase con el archivo config.toml.
Paso 3: crear Edge Function
supabase functions new hello-world
Se genera supabase/functions/hello-world/index.ts con un contenido similar a:
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
Deno.serve(async (req) => {
const data = {
message: "Hello from Edge Function!"
}
return new Response(JSON.stringify(data), {
headers: { "Content-Type": "application/json" }
})
})
Puedes adaptarlo a tu lógica. Por ejemplo, recibir un parámetro name y devolver un saludo:
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
Deno.serve(async (req) => {
// Solo acepta peticiones POST
if (req.method !== "POST") {
return new Response("Method not allowed", { status: 405 })
}
try {
const body = await req.json()
const name = body.name || "Stranger"
return new Response(JSON.stringify({
message: `Hey ${name}, welcome to the edge!`,
timestamp: new Date().toISOString()
}), {
headers: { "Content-Type": "application/json" }
})
} catch (err) {
return new Response(JSON.stringify({ error: "Invalid JSON" }), {
status: 400,
headers: { "Content-Type": "application/json" }
})
}
})
Paso 4: prueba local
Supabase CLI permite ejecutar Edge Functions en local para depurar:
supabase functions serve --no-verify-jwt
Arranca un servicio en el puerto 54321 por defecto. Puedes probar con curl:
curl -X POST http://localhost:54321/functions/v1/hello-world \
-H "Content-Type: application/json" \
-d '{"name":"Easton"}'
# Respuesta:
# {"message":"Hey Easton, welcome to the edge!","timestamp":"2026-05-03T14:30:00.000Z"}
--no-verify-jwt omite la verificación JWT para facilitar las pruebas locales. En producción conviene activarla.
Paso 5: desplegar a nivel global
Cuando la prueba local funcione, despliega en la red edge de Supabase:
# Iniciar sesión (si aún no lo has hecho)
supabase login
# Vincular tu proyecto
supabase link --project-ref <your-project-id>
# Desplegar la función
supabase functions deploy hello-world
Al desplegar, Supabase distribuye la función a nodos edge de todo el mundo. En el Dashboard verás los logs de deployment y la URL.
Paso 6: probar la invocación
Tras el despliegue, la URL tiene este formato:
https://<project-id>.supabase.co/functions/v1/hello-world
Invócala con curl:
curl -X POST https://<project-id>.supabase.co/functions/v1/hello-world \
-H "Authorization: Bearer <anon-key>" \
-H "Content-Type: application/json" \
-d '{"name":"World"}'
Fíjate en el header Authorization. Supabase Edge Functions verifica JWT por defecto; necesitas la anon key del proyecto o el JWT del usuario.
¿Para qué sirven las Edge Functions en la práctica? Además de la demo, hay muchos casos de uso:
Procesamiento de webhooks
Por ejemplo, cuando Stripe envía un webhook tras un pago exitoso, una Edge Function puede recibirlo y escribir en la base de datos:
// supabase/functions/stripe-webhook/index.ts
import "jsr:@supabase/functions-js/edge-runtime.d.ts"
import { createClient } from "jsr:@supabase/supabase-js@2"
Deno.serve(async (req) => {
// Verificar firma de Stripe (simplificado; en producción usar verificación hmac)
const event = await req.json()
const supabase = createClient(
Deno.env.get("SUPABASE_URL")!,
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
)
if (event.type === "payment_intent.succeeded") {
const payment = event.data.object
await supabase.from("payments").insert({
id: payment.id,
amount: payment.amount,
customer_id: payment.customer,
created_at: new Date().toISOString()
})
}
return new Response(JSON.stringify({ received: true }), {
headers: { "Content-Type": "application/json" }
})
})
Proxy de API
¿Alguna API de terceros requiere API Key y no quieres exponerla al frontend? Usa una Edge Function como proxy:
// supabase/functions/openai-proxy/index.ts
Deno.serve(async (req) => {
const body = await req.json()
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": `Bearer ${Deno.env.get("OPENAI_API_KEY")}`,
"Content-Type": "application/json"
},
body: JSON.stringify(body)
})
return new Response(response.body, {
headers: { "Content-Type": "application/json" }
})
})
El frontend llama a tu Edge Function y la API Key queda oculta en el nodo edge.
4. Decisión de arquitectura: Supabase vs Cloudflare Workers
En computación edge muchos preguntan: ¿Cloudflare Workers o Supabase Edge Functions?
No son competidores directos. El escenario marca la elección.
Comparación de rendimiento
En arranque en frío, Cloudflare Workers gana. Los datos oficiales: ~30 ms frente a ~120 ms en Supabase Edge Functions.
¿Por qué? El runtime de Workers de Cloudflare es propio y optimizado para edge. Supabase usa Deno, que también es rápido, pero añade la capa de compilación de TypeScript.
En la práctica, en la mayoría de escenarios la diferencia entre 120 ms y 30 ms no la nota el usuario: la variación de red de la propia petición suele ser mayor. Pero en trading de alta frecuencia o subastas en tiempo real, donde cada milisegundo cuenta, Cloudflare Workers encaja mejor.
Comparación de integración
Aquí brilla Supabase. Con Edge Functions puedes conectar directamente al Postgres del mismo proyecto, usar Auth y Storage. Las variables de entorno se inyectan solas, sin configuración extra.
Con Cloudflare Workers debes resolver la conexión a base de datos por tu cuenta. Puedes usar Cloudflare D1 (su SQLite edge) o una base externa, pero requiere más trabajo de configuración.
Vendor lock-in
Cloudflare Workers usa un runtime cerrado. Tu código solo corre en Cloudflare; cambiar de plataforma implica reescribir.
Supabase Edge Functions usa Deno open source. En teoría puedes mover el mismo código a Deno Deploy o autoalojar Edge Runtime. La red edge de Supabase no se mueve, pero a nivel de runtime no quedas bloqueado.
Comparación de ecosistema
El ecosistema de Cloudflare Workers es más maduro. Lleva desde 2017 y tiene herramientas, frameworks y experiencia de comunidad. Hono y Remix soportan el runtime de Workers.
Supabase Edge Functions llegó en 2022 y el ecosistema sigue creciendo. Al usar Deno estándar, muchas librerías de Deno funcionan directamente.
Recomendaciones de elección
Según tu situación, esta matriz orientativa ayuda:
| Tu situación | Recomendación |
|---|---|
| Ya usas Supabase (Auth, Database, Storage) | Supabase Edge Functions |
| Solo computación edge, sin base de datos | Cloudflare Workers |
| Preocupación por vendor lock-in | Supabase Edge Functions (Deno open source) |
| Buscar arranque en frío extremo (<50 ms) | Cloudflare Workers |
| Necesitas Postgres directo desde el borde | Supabase Edge Functions |
Yo combino ambos: Cloudflare Workers para proxy inverso y caché en el frontend, Supabase Edge Functions para Auth y operaciones de base de datos. Cada plataforma en lo suyo.
5. Errores que cometí y buenas prácticas
Comparto los fallos que tuve en producción para que los evites.
Primer error: usar paquetes de Node.js
Quise usar axios para HTTP y escribí import axios from "axios". Al desplegar falló: módulo no encontrado.
Edge Functions usa Deno, no Node.js. Los paquetes npm no funcionan directamente. Cambia a paquetes compatibles con Deno o usa la API fetch nativa, que suele bastar:
// No uses axios
// import axios from "axios" // Esta línea fallará
// Usa fetch
const response = await fetch("https://api.example.com/data", {
method: "GET",
headers: { "Authorization": "Bearer xxx" }
})
const data = await response.json()
Si buscas algo parecido a axios, en el ecosistema Deno hay alternativas como ky.
Segundo error: función demasiado larga
Escribí una función por lotes que recorría miles de registros. En local iba bien; desplegada se cortaba a los 30 segundos.
El motivo: Edge Functions tiene límite de tiempo de CPU. Según la documentación, el Isolate tiene un tope de 400 s (límites blando y duro). Si lo superas, el proceso se termina.
Solución: no hagas trabajo pesado en Edge Functions. El borde sirve para lógica ligera — validación, reenvío, cálculos simples. Tareas por lotes complejas van al servidor central o a un Worker dedicado.
Tercer error: forma incorrecta de conectar la base de datos
En edge, una conexión larga tradicional a Postgres es problemática. Muchos nodos edge, cada uno con una conexión persistente, y el pool de la base de datos se satura rápido.
Usa el pool de conexiones (Pooler) de Supabase o crea conexiones cortas por petición y libéralas al instante. La variable SUPABASE_DB_URL apunta al Pooler:
import { Pool } from "https://deno.land/x/[email protected]/mod.ts"
const pool = new Pool(Deno.env.get("SUPABASE_DB_URL")!, 10)
Deno.serve(async (req) => {
const client = await pool.connect()
try {
const result = await client.queryArray("SELECT * FROM users LIMIT 10")
return new Response(JSON.stringify(result.rows))
} finally {
client.release() // ¡Recuerda liberar la conexión!
}
})
Cuarto error: JWT sin configurar
En local usé --no-verify-jwt para depurar. Al desplegar olvidé activar la verificación y cualquiera podía invocar la función. Riesgo de seguridad serio.
Configúralo en config.toml:
[functions.hello-world]
verify_jwt = true
O al desplegar:
supabase functions deploy hello-world --verify-jwt
Algunos trucos útiles
- Usar Hono en lugar de Deno.serve nativo
Hono es un framework web ultraligero pensado para edge. Soporta rutas y middleware con solo 13 KB. Frente al peso de Express, encaja muy bien en Edge Functions:
import { Hono } from "jsr:@hono/hono"
import { cors } from "jsr:@hono/hono/cors"
const app = new Hono()
app.use("*", cors())
app.get("/health", (c) => c.json({ status: "ok" }))
app.post("/echo", async (c) => {
const body = await c.req.json()
return c.json({ echo: body })
})
Deno.serve(app.fetch)
- Gestión de variables de entorno
Supabase Edge Functions tiene dos runtimes: Main Runtime (controlado por la plataforma) y User Runtime (tu código). Los permisos de variables difieren:
SUPABASE_URL,SUPABASE_ANON_KEY,SUPABASE_SERVICE_ROLE_KEYse inyectan automáticamente- Variables personalizadas en Dashboard o CLI:
supabase secrets set MY_VAR=value
- Import Map para reducir resolución repetida
Si la función depende de muchos módulos externos, un Import Map predefinido evita resolver URLs en cada petición:
// deno.json o import_map.json
{
"imports": {
"hono": "jsr:@hono/hono",
"supabase-js": "jsr:@supabase/supabase-js@2"
}
}
Luego en el código usas nombres cortos:
import { Hono } from "hono"
import { createClient } from "supabase-js"
Resumen
En una frase: Supabase Edge Functions lleva tu código al nodo más cercano al usuario, en el runtime seguro de Deno, con arranque en frío de 120 ms y distribución global automática.
Si tu proyecto ya usa Supabase — Auth, Database o Storage — Edge Functions es la extensión natural. Sin pelearte con la conexión a base de datos ni configurar Auth por separado: todo encaja. ¿Miedo al vendor lock-in? Deno es open source y Edge Runtime se puede autoalojar. Al menos tienes una salida.
¿Siguiente paso? Abre el Dashboard de Supabase y sigue el Quickstart. En 10 minutos tu primera Edge Function estará corriendo en nodos edge de todo el mundo.
Otros artículos de la serie:
- Supabase para empezar: PostgreSQL + Auth + Storage en un solo backend — visión general de Supabase
- Supabase Auth en la práctica: verificación por email, OAuth y gestión de sesiones — Auth en producción
- Supabase Auth avanzado: OAuth, SSO y control de permisos — configuración avanzada
Si te interesa más Cloudflare Workers, mira también: Guía práctica de Cloudflare Workers. Cada plataforma tiene sus fortalezas; elige la que mejor encaje contigo.
Desplegar tu primera Supabase Edge Function
Crear, probar y desplegar una Edge Function en la red edge global desde cero
⏱️ Estimated time: 10 min
- 1
Step 1: Instalar Supabase CLI
Instala Supabase CLI de forma global:
```bash
npm install -g supabase
```
Después ejecuta `supabase --version` para verificar la instalación. - 2
Step 2: Inicializar el proyecto
En el directorio del proyecto ejecuta:
```bash
supabase init
```
Esto crea el directorio `supabase` y el archivo de configuración `config.toml`. - 3
Step 3: Crear Edge Function
Crea una nueva Edge Function con la CLI:
```bash
supabase functions new hello-world
```
La función generada está en `supabase/functions/hello-world/index.ts` y devuelve una respuesta JSON por defecto. - 4
Step 4: Prueba local
Inicia el servidor de desarrollo local:
```bash
supabase functions serve --no-verify-jwt
```
Puerto por defecto 54321. Prueba con curl o Postman:
```bash
curl -X POST http://localhost:54321/functions/v1/hello-world \
-H "Content-Type: application/json" \
-d '{"name":"Easton"}'
``` - 5
Step 5: Desplegar en la red edge global
Tras iniciar sesión y vincular el proyecto, despliega:
```bash
supabase login
supabase link --project-ref <your-project-id>
supabase functions deploy hello-world
```
Al terminar, consulta la URL de la función y los logs en el Dashboard. - 6
Step 6: Probar la invocación
Invoca con la URL de la función y el token de autenticación:
```bash
curl -X POST https://<project-id>.supabase.co/functions/v1/hello-world \
-H "Authorization: Bearer <anon-key>" \
-H "Content-Type: application/json" \
-d '{"name":"World"}'
```
En producción conviene activar la verificación JWT: `supabase functions deploy hello-world --verify-jwt`
FAQ
¿En qué se diferencian Supabase Edge Functions y AWS Lambda?
¿Pueden las Edge Functions usar paquetes npm?
¿Hay límite de tiempo de ejecución en Edge Functions?
¿Cómo conectar Postgres desde una Edge Function?
• Usa la variable de entorno `SUPABASE_DB_URL` (apunta automáticamente al Pooler)
• Crea un pool con el paquete `postgres`
• Libera la conexión tras cada petición (`client.release()`)
Evita conexiones largas tradicionales: muchos nodos edge pueden agotar el pool.
¿Cómo elegir entre Supabase Edge Functions y Cloudflare Workers?
• Ya usas el stack Supabase → Edge Functions (integración profunda, desarrollo rápido)
• Solo computación edge sin backend → Cloudflare Workers (arranque en frío ~30 ms, más rápido)
• Preocupación por vendor lock-in → Edge Functions (Deno es open source y se puede autoalojar)
• Necesitas Postgres directo desde el borde → Edge Functions (integración fluida)
Puedes combinar ambos: Cloudflare Workers para proxy y caché en el frontend, Edge Functions para Auth y lógica de base de datos.
¿Cómo configurar la verificación JWT para proteger una Edge Function?
• En el archivo de configuración: añade en `config.toml` `[functions.hello-world] verify_jwt = true`
• Por línea de comandos: añade `--verify-jwt` al desplegar
En pruebas locales usa `--no-verify-jwt` para omitir la verificación, pero en producción actívala siempre. Sin JWT, cualquiera podría invocar tu función.
14 min de lectura · Publicado el: 3 may 2026 · Actualizado el: 21 ago 2026
Supabase en práctica
Si llegaste desde búsqueda, lo más rápido es ir al artículo anterior o siguiente de esta misma serie.
Anterior
Configuración en profundidad de Supabase Auth: OAuth, SSO y control de permisos
Explicación detallada de la configuración avanzada de Supabase Auth: integración de múltiples proveedores de OAuth, autenticación empresarial SAML SSO, aislamiento de permisos de múltiples inquilinos RLS, una solución de autenticación completa desde aplicaciones de consumo hasta SaaS empresarial
Parte 9 de 10
Siguiente
Este es el artículo más reciente de la serie por ahora.



Comentarios
Inicia sesión con GitHub para dejar un comentario