n8n no debería reemplazar todo tu backend
Límites de herramientas low-code como n8n: cuándo automatizar y cuándo escribir software de verdad.

Hace unos meses vi algo que me preocupó. Un equipo había construido toda su lógica de negocio dentro de n8n. No hablo de enviar emails cuando alguien se registra o de sincronizar datos entre dos servicios. Hablo de validación de pedidos, cálculo de precios con descuentos escalonados, gestión de estados de envío y generación de facturas. Todo en workflows visuales con decenas de nodos, condicionales anidados y funciones JavaScript inline. Cuando algo fallaba, nadie sabía dónde mirar. Cuando necesitaban cambiar una regla de negocio, tocaban tres workflows distintos y rezaban para no romper los otros.
n8n es una herramienta excelente para lo que fue diseñada: automatizar integraciones, conectar servicios y ejecutar flujos que de otro modo serían glue code repetitivo. Pero no es un framework de desarrollo de software. Y tratarla como tal tiene consecuencias que aparecen tarde, cuando ya duelen.
El problema no es n8n, es dónde lo pones
Quiero ser claro desde el principio: no estoy en contra de n8n ni del low-code en general. Lo uso a diario para automatizaciones que me ahorran horas de trabajo. El problema aparece cuando la herramienta se convierte en el sistema completo en vez de ser una pieza del sistema.
El low-code funciona mejor como pegamento entre sistemas que como cimiento de una aplicación.
He visto este patrón repetirse en tres fases:
- Fase luna de miel. Montas un workflow rápido, funciona, todos contentos. “Mira, sin escribir código.”
- Fase expansión. Empiezas a añadir lógica. Condicionales, bucles, transformaciones. El workflow crece. Sigue funcionando.
- Fase dolor. El workflow tiene 60 nodos. Nadie recuerda por qué hay un IF en el nodo 23. Un cambio en la API externa rompe tres ramas. No hay tests. No hay logs claros. Debugging es hacer click en cada nodo a ver qué salió.
Reglas de decisión: cuándo n8n, cuándo código
Después de usar n8n durante bastante tiempo y haberme equivocado más de una vez, tengo un conjunto de criterios que aplico antes de decidir si algo va en un workflow o en código propio.
Va en n8n cuando…
- Es glue code. Conectar servicio A con servicio B. Recibir un webhook y reenviar datos transformados. Sincronizar un CRM con una base de datos.
- La lógica es lineal o tiene pocas ramas. Si puedes describir el flujo en una frase (“cuando llega un pedido, envía un email y actualiza el CRM”), probablemente encaja en un workflow.
- No necesita tests unitarios. Si la lógica es tan simple que un test sería trivial, un workflow es suficiente.
- El mantenimiento lo puede hacer alguien que no es programador. Si quieres que marketing pueda cambiar el texto de una notificación sin pedírselo a desarrollo.
- Es un prototipo. Estás validando una idea. Si funciona, ya lo extraerás a código.
Va en código cuando…
- Hay lógica de negocio compleja. Cálculos con reglas que dependen de múltiples condiciones, estados, configuraciones.
- Necesitas tests. Si una regla mal implementada puede causar un problema de negocio, necesitas tests automatizados. En n8n no hay framework de testing integrado.
- Hay concurrencia o estado. Múltiples procesos accediendo a los mismos datos, race conditions, transacciones que deben ser atómicas.
- El flujo tiene más de 15-20 nodos con condicionales. Es una señal clara de que la complejidad ha superado lo que un workflow visual puede gestionar de forma legible.
- Necesitas versionado y code review. Los workflows de n8n se pueden exportar como JSON, pero hacer diff de dos JSONs de 500 líneas en un PR no es lo mismo que revisar código.
Ejemplos concretos
Ejemplo 1: Notificación de nuevo registro (n8n)
Un usuario se registra en tu app. Quieres enviar un email de bienvenida y notificar al equipo por Slack.
Esto es textbook n8n. Flujo lineal, sin lógica compleja, integraciones estándar.
Webhook (nuevo usuario)
→ Enviar email de bienvenida (SendGrid)
→ Notificar a Slack (#nuevos-usuarios)
→ Guardar en Google Sheets (registro de onboarding)No tiene sentido escribir un servicio para esto. n8n lo resuelve en 10 minutos.
Ejemplo 2: Cálculo de precios con descuentos (API propia)
El precio final de un pedido depende de: tipo de cliente, volumen del pedido, promociones activas, descuentos por fidelidad, impuestos por región, y reglas de envío gratuito que cambian cada mes.
Esto NO debería estar en n8n. Las razones:
# pricing_service.py - FastAPI
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from decimal import Decimal
app = FastAPI()
class OrderRequest(BaseModel):
customer_id: str
items: list[dict]
region: str
promo_code: str | None = None
class PricingResult(BaseModel):
subtotal: Decimal
discount: Decimal
tax: Decimal
shipping: Decimal
total: Decimal
rules_applied: list[str]
@app.post("/calculate-price", response_model=PricingResult)
def calculate_price(order: OrderRequest):
customer = get_customer(order.customer_id)
subtotal = sum_items(order.items)
# Reglas de descuento
discount = Decimal("0")
rules = []
# Descuento por volumen
if subtotal > Decimal("500"):
discount += subtotal * Decimal("0.05")
rules.append("volume_5pct")
# Descuento por fidelidad
if customer.loyalty_tier == "gold":
discount += subtotal * Decimal("0.10")
rules.append("loyalty_gold_10pct")
# Promoción activa
if order.promo_code:
promo_discount = apply_promo(order.promo_code, subtotal)
discount += promo_discount
rules.append(f"promo_{order.promo_code}")
# Impuestos por región
tax = calculate_tax(subtotal - discount, order.region)
# Envío gratuito
shipping = Decimal("0") if (subtotal - discount) > Decimal("100") else Decimal("4.99")
if shipping == Decimal("0"):
rules.append("free_shipping")
return PricingResult(
subtotal=subtotal,
discount=discount,
tax=tax,
shipping=shipping,
total=subtotal - discount + tax + shipping,
rules_applied=rules,
)Esto tiene tests, versionado, logs, y se puede revisar en un PR. Si una regla cambia, sabes exactamente dónde tocar.
Ejemplo 3: Sincronización de inventario (depende)
Cada hora necesitas leer el inventario de un ERP y actualizar una base de datos que consulta tu app.
Si la sincronización es directa (leer, transformar ligeramente, escribir), n8n vale. Si la sincronización tiene reglas de conflicto, prioridades entre fuentes, o lógica de reconciliación, mejor un script o servicio.
Los riesgos de poner lógica compleja en workflows
Debugging
Cuando un workflow de n8n falla, la forma de investigar es ir nodo por nodo viendo qué datos entraron y qué datos salieron. No hay stack traces claros. No hay breakpoints. No hay logging estructurado. Para un flujo de 5 nodos es manejable. Para uno de 40 nodos con ramas condicionales, es un infierno.
Testing
n8n no tiene un framework de testing. No puedes escribir unit tests para la lógica de un nodo. No puedes hacer mocking de servicios externos. No puedes correr una suite de tests en CI/CD antes de desplegar un cambio. Si tu lógica de negocio está en n8n, no tiene tests. Así de simple.
Versionado
Los workflows se exportan como JSON. Puedes meterlos en git, pero:
- Los diffs son enormes e ilegibles.
- No hay herramienta de merge que entienda la estructura de un workflow.
- Un cambio cosmético (mover un nodo de posición en el canvas) genera un diff que oculta el cambio real.
{
"nodes": [
{
"parameters": {
"functionCode": "const items = $input.all();\n// 47 líneas de JavaScript..."
},
"name": "Calculate Price",
"type": "n8n-nodes-base.function",
"position": [820, 340]
}
]
}Revisar eso en un PR es muy distinto a revisar un archivo Python con funciones bien nombradas.
Dependencia de personas
Cuando la lógica está en código, cualquier desarrollador puede entenderla leyendo el archivo. Cuando está en un workflow visual, necesitas abrir n8n, navegar por los nodos, entender las conexiones, y a menudo interpretar JavaScript inline escrito de forma compacta. La curva de aprendizaje para mantener un workflow complejo es más alta de lo que parece.
Cuándo extraer a una API propia
Si ya tienes lógica compleja en n8n y estás sufriendo alguno de los problemas que he descrito, el patrón de extracción que mejor me funciona es:
- Identifica la lógica de negocio dentro del workflow. Normalmente es un nodo Function o un bloque de nodos con condicionales.
- Mueve esa lógica a un servicio (FastAPI si tu stack es Python, Spring Boot si es JVM).
- El workflow de n8n llama a tu servicio por HTTP. n8n se queda como orquestador, no como motor de lógica.
Antes:
Webhook → [40 nodos de lógica en n8n] → Respuesta
Después:
Webhook → HTTP Request a tu API → Respuesta
(la lógica está en tu servicio, con tests y versionado)Este patrón mantiene la ventaja de n8n (orquestación visual, integraciones fáciles) sin sus desventajas (debugging, testing, versionado de lógica).
Tabla comparativa: workflow n8n vs API propia
| Aspecto | Workflow n8n | API propia |
|---|---|---|
| Velocidad de prototipado | Muy alta | Media |
| Facilidad de mantenimiento | Baja si hay lógica compleja | Alta con buenas prácticas |
| Testing | No hay framework integrado | Unit tests, integration tests, CI/CD |
| Debugging | Nodo por nodo, visual | Logs, stack traces, breakpoints |
| Versionado | JSON diffs ilegibles | Git diffs claros |
| Code review | Muy difícil | Estándar |
| Escalabilidad | Limitada | Según tu diseño |
| Curva de aprendizaje | Baja al principio | Media-alta |
| Integraciones | Cientos de nodos listos | Tú las implementas |
| Coste de desarrollo | Bajo para flujos simples | Mayor inversión inicial |
| Dependencia de la herramienta | Alta (vendor lock-in visual) | Baja (código estándar) |
Cuándo mantener en n8n
No todo necesita extraerse a código. Estas son las tareas que mantengo en n8n sin remordimientos:
- Notificaciones. Emails, Slack, Telegram. Flujos lineales, sin lógica de negocio.
- Sincronización simple de datos. Leer de una API, transformar un par de campos, escribir en otra.
- Webhooks de paso. Recibir un evento y reenviarlo a otro servicio con formato diferente.
- Tareas programadas simples. Cada lunes a las 9, exportar un CSV de la base de datos y enviarlo por email.
- Prototipos. Validar una idea de integración antes de invertir en código.
Si puedes describir lo que hace tu workflow en una frase de menos de 20 palabras, probablemente está bien en n8n. Si necesitas un párrafo, probablemente no.
El patrón que me funciona
Mi arquitectura actual con n8n sigue este principio: n8n orquesta, el código decide.
┌──────────────┐
│ n8n │
│ (orquestador)│
└──────┬───────┘
│
┌──────────────┼──────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌──────────┐
│ FastAPI │ │ Servicios │ │ Bases de │
│ (lógica) │ │ externos │ │ datos │
└────────────┘ └────────────┘ └──────────┘n8n recibe eventos, programa ejecuciones y conecta servicios. Cuando hay una decisión de negocio, llama a una API que tiene la lógica, los tests y el versionado que necesita. Lo mejor de ambos mundos.
Lo que no quiero que entiendas mal
Este artículo no es una crítica a n8n. Es una crítica a usarlo para lo que no está diseñado. Es como usar Excel como base de datos: funciona hasta que no funciona, y cuando deja de funcionar duele mucho.
n8n es una herramienta fantástica en su dominio. He montado automatizaciones con n8n que me habrían costado días de desarrollo si las hubiera escrito en código. La clave es saber cuándo estás automatizando y cuándo estás programando. Si estás programando, usa herramientas de programación.
La próxima vez que te encuentres escribiendo una función de 50 líneas de JavaScript dentro de un nodo Function de n8n, párate un momento y pregúntate: “¿Esto debería estar aquí?”. Si la respuesta no es un sí inmediato, probablemente sea el momento de abrir tu IDE.


