Arquitectura de un backend event‑driven con Supabase y n8n para disparar workflows de IA sin servidores propios
Tiempo estimado de lectura: 5 min
- Usa la base de datos como bus de eventos para desacoplar la lógica de IA del core y evitar timeouts en serverless.
- n8n como orquestador para descargar, chunkear, generar embeddings y llamar al LLM, con reintentos y observabilidad visual.
- Supabase Realtime + pgvector para almacenar embeddings y actualizar el frontend al completar workflows sin polling.
- Seguridad y idempotencia mediante RLS, estados de filas y locks lógicos.
Tabla de contenidos
Integrar IA en un SaaS ya en marcha suena a reescribir la app entera. No tiene por qué ser así. En este artículo te explico, paso a paso y con criterio técnico, cómo añadir features de IA (RAG) usando una arquitectura event‑driven sobre Next.js + Supabase y n8n —sin montar servidores propios— y con ejemplos prácticos para ponerlo en producción rápido.
Resumen rápido (lectores con prisa)
Usa la base de datos como bus de eventos: el frontend escribe filas, Supabase dispara webhooks a n8n, n8n ejecuta workflows (descarga, chunking, embeddings, LLM) y actualiza la DB. El frontend escucha Realtime y muestra resultados.
Beneficios: evita timeouts de serverless, desacopla la lógica de IA, facilita reintentos y observabilidad. Casos de uso: tareas asíncronas que toleran segundos/minutos de latencia.
No recomendado para inferencia sub‑1s. Implementación mínima: pgvector + RPC para búsquedas semánticas, n8n para orquestar y Supabase Realtime para UX.
SaaS y stack Next.js + Supabase: arquitectura event‑driven para IA (qué, por qué y cómo)
Esquema rápido
- Frontend Next.js inserta fila en tabla (uploads / queries).
- Supabase Database Webhook → POST a n8n.
- n8n: descarga, chunking, embeddings, búsqueda vectorial, llamada al LLM.
- n8n actualiza tabla con resultado.
- Frontend recibe update vía Supabase Realtime.
Por qué es mejor que hacerlo síncrono en una API Route de Next.js:
- Avoid limits and timeouts imposed by serverless platforms such as Vercel.
- Desacoplas la lógica de IA del código núcleo.
- Ganas observabilidad y reintentos con n8n sin escribir infra.
Documentación relevante:
SQL mínimo para empezar (Supabase + pgvector)
Ejecuta en el SQL editor de Supabase:
create extension if not exists vector;
create table documents (
id bigserial primary key,
content text,
metadata jsonb,
embedding vector(1536)
);
create index on documents using hnsw (embedding vector_cosine_ops);
Y una función RPC para consultas semánticas:
create or replace function match_documents(query_embedding vector(1536), threshold float, topk int)
returns table (id bigint, content text, metadata jsonb, similarity float) as $
select id, content, metadata, 1 - (embedding <=> query_embedding) as similarity
from documents
where 1 - (embedding <=> query_embedding) > threshold
order by embedding <=> query_embedding
limit topk;
$ language sql stable;
Workflow de ingestión (n8n) – resumen práctico
Trigger: Webhook (desde Database Webhook de Supabase).
- Nodo: descargar archivo desde Supabase Storage.
- Nodo: extraer texto (PDF → OCR si hace falta).
- Nodo: Text splitter (chunks ~500 tokens, overlap 50).
- Nodo: OpenAI embeddings (o proveedor elegido) → vectores.
- Nodo: insertar en tabla documents en Supabase.
n8n maneja reintentos, logs y branching visual. Documentación de n8n: n8n docs.
Workflow de consulta RAG (n8n)
Trigger: Webhook cuando se inserta una query (tabla queries).
- Genera embedding de la pregunta.
- Llama a la RPC
match_documentsen Supabase para obtener contexto (top K). - Construye prompt (contextos + instrucción + pregunta).
- Llama al LLM (chat/completions).
- Actualiza la fila queries con la respuesta y el estado (processing → done).
Integración en Next.js (realtime)
En el cliente, suscríbete a cambios para mostrar resultados en cuanto n8n escriba la respuesta:
useEffect(() => {
const channel = supabase.channel('queries')
.on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'queries' }, payload => {
// actualizar UI con payload.new
})
.subscribe();
return () => supabase.removeChannel(channel);
}, []);
Consideraciones prácticas y trampas habituales
- Seguridad: mantén RLS activado. n8n puede usar service_role para escribir, pero el frontend solo debe acceder con claves anónimas y políticas RLS.
- Idempotencia: marca filas con status (pending/processing/done) y locks lógicos para evitar doble procesamiento.
- Costes: planifica coste por embeddings y llamadas LLM. Embeddings suelen ser baratos, pero el prompt engineering y el tamaño del contexto importan.
- Escala: para >1k events/min, considera fan‑out a múltiples instancias n8n o introducir una cola (RabbitMQ / Redis) entre Webhook y n8n.
- Dev local: webhooks requieren URL pública (ngrok / localtunnel / host.docker.internal en Docker).
Cuándo usar (y cuándo no)
Úsalo cuando quieras añadir IA compleja a un SaaS existente sin reescribir el backend, cuando los procesos durarán segundos o minutos, y cuando la UX pueda ser asíncrona.
No lo uses si necesitas inferencia ultrarrápida (sub-1s) o toleras latencias síncronas controladas.
Cierre
Este patrón transforma la base de datos en el interruptor que enciende la IA. Añades memoria, buscas semánticamente y produces respuestas sin tocar el core de tu aplicación. Implementarlo con Next.js + Supabase + n8n te da velocidad de entrega, observabilidad y mantenibilidad —y te deja tiempo para mejorar prompts en vez de pelear con infra.
Dominicode Labs
Si buscas ejemplos reutilizables y plantillas de workflows para acelerar la adopción de este patrón, revisa los recursos de Dominicode Labs. Encontrarás guías prácticas y snippets que encajan con Next.js, Supabase y n8n para producción.
FAQ
¿Por qué usar la base de datos como bus de eventos?
Porque permite desacoplar al productor (frontend) del consumidor (n8n) sin añadir infra adicional. Supabase puede emitir webhooks cuando cambian filas y la DB actúa como registro de estado y fuente de verdad.
También facilita la observabilidad, reintentos y recuperación: el estado de cada evento queda en la base de datos.
¿Cómo evito procesar la misma fila dos veces?
Usa estados en la fila (pending → processing → done) y realiza una operación atómica para marcar processing antes de trabajar. Implementa idempotencia en n8n y chequeos basados en un identificador único.
También es recomendable usar locks lógicos o columnas de processed_at para detectar trabajo ya realizado.
¿Qué hago con los secretos (API keys) en n8n?
Almacena claves en las credenciales/secretos de n8n, no en la base de datos pública. Para acciones en la DB, n8n puede usar el service_role de Supabase; el frontend solo utiliza la clave anónima y RLS.
¿Puedo usar otro orquestador que no sea n8n?
Sí. El patrón es agnóstico: cualquier sistema que reciba webhooks y ejecute workflows (AWS Step Functions, Temporal, custom workers) sirve. n8n aporta rapidez de implementación y UI visual para branching y reintentos.
¿Cómo escalo si recibo miles de eventos por minuto?
Considera fan‑out a múltiples instancias de n8n, introducir una cola dedicada (RabbitMQ / Redis) entre el webhook y los workers, o sharding en la base de datos. Monitoriza latencias y coste por embedding/LLM para identificar cuellos.
¿Dónde coloco el chunking y la extracción de texto?
En el workflow de ingestión (n8n). Descarga el archivo, extrae texto (OCR si es necesario), aplica text splitter (chunks ~500 tokens, overlap 50) y luego genera embeddings antes de insertar los vectores en la tabla documents.
