Workflow Exit

Qué se rompe al pasar los pasos de código de Pipedream a n8n Cloud

Actualizado el 13 de octubre de 2026

En n8n Cloud, el nodo Code solo puede cargar dos módulos, crypto y moment, y el código Python no puede importar nada, ni siquiera la biblioteca estándar (documentación del nodo Code de n8n). Los pasos de código de Pipedream que importan axios, date-fns, un SDK o cualquier otro paquete npm fallan hasta que los reemplaces por funciones integradas de n8n, como this.helpers.httpRequest y Luxon, o hasta que pases a n8n self-hosted con NODE_FUNCTION_ALLOW_EXTERNAL. Los helpers propios de Pipedream (steps, $.export, $.respond, data stores, process.env) también necesitan equivalentes en n8n.

Pipedream Workflows está en modo de mantenimiento desde el 30 de septiembre de 2026 y deja de funcionar el 31 de marzo de 2027, así que para entonces cada paso de código necesita un nuevo runtime. El límite de npm es lo que más tiempo lleva, porque Pipedream te dejaba usar npm sin restricciones: escribías import axios from "axios" y Pipedream lo instalaba al desplegar (documentación de Node.js de Pipedream). Una persona que revisó exportaciones reales de Pipedream en el foro de la comunidad de n8n lo resumió así: "Cerca de 7 de cada 10 pasos de código que revisé importan un paquete o llaman a una API" (comunidad de n8n).

Pipedream vs n8n Cloud vs n8n self-hosted

Capacidad Paso de código de Pipedream Nodo Code de n8n Cloud Nodo Code de n8n self-hosted
Paquetes npm Cualquiera, instalado al desplegar Solo crypto y moment Cualquier módulo instalado que esté en NODE_FUNCTION_ALLOW_EXTERNAL
Módulos integrados de Node.js (fs, path) Sí No Si están en NODE_FUNCTION_ALLOW_BUILTIN
Sintaxis de módulos import o require Solo require Solo require
Paquetes de Python Cualquier paquete de PyPI Ninguno, ni siquiera la biblioteca estándar Si están en la imagen del task runner y en la lista de permitidos
Peticiones HTTP Cualquier cliente this.helpers.httpRequest o nodo HTTP Request Lo mismo, o un cliente npm permitido
Fechas Cualquier biblioteca DateTime de Luxon integrado, además de moment Lo mismo, o una biblioteca permitida
Variables de entorno process.env $vars en Pro y Enterprise $vars en Business y Enterprise, o $env si está habilitado
Tokens de cuentas conectadas this.app.$auth Los nodos Code no pueden leer credenciales Lo mismo
Estado clave-valor Data stores Datos estáticos o Data Tables Lo mismo
Archivos /tmp y File Stores Sin sistema de archivos fs si está permitido, o nodos de archivos

Fuentes: nodo Code, habilitar módulos, problemas comunes.

1. Clientes HTTP: axios, got, node-fetch

n8n ofrece this.helpers.httpRequest dentro del nodo Code (referencia de opciones). Por defecto devuelve el cuerpo de la respuesta, lo que coincide justo con lo que devolvía el axios de @pipedream/platform cuando la petición salía bien.

Antes, en Pipedream:

import axios from "axios";

export default defineComponent({
  async run({ steps, $ }) {
    const { data } = await axios.get("https://api.example.com/orders", {
      params: { status: "open" },
      headers: { Authorization: `Bearer ${process.env.SHOP_TOKEN}` },
    });
    return data;
  },
});

Después, en un nodo Code de n8n (modo: Run Once for All Items):

const orders = await this.helpers.httpRequest({
  method: "GET",
  url: "https://api.example.com/orders",
  qs: { status: "open" },
  headers: { Authorization: `Bearer ${$vars.SHOP_TOKEN}` },
  json: true,
});

// An item's json must be an object, so wrap the array.
return [{ json: { orders } }];

Los nombres de las opciones no son los mismos que en axios: params pasa a ser qs y data pasa a ser body. Usa returnFullResponse: true cuando necesites el código de estado y los encabezados; entonces recibes { body, headers, statusCode, statusMessage }.

En las llamadas que usan una cuenta conectada, no muevas el token al código. Por diseño, los nodos Code de n8n no pueden acceder a las credenciales (documentación de n8n). Pon esa petición en un nodo HTTP Request, elige el tipo de credencial predefinido de la app y deja que n8n se encargue de renovar el token OAuth. Un paso que leía this.github.$auth.oauth_access_token se convierte en un nodo HTTP Request con una credencial de GitHub.

2. Fechas: date-fns, dayjs, moment-timezone

n8n incluye Luxon, y su documentación sobre fechas presenta DateTime como la opción recomendada. Este ejemplo viene del propio workflow de muestra de GitHub Sync de Pipedream.

Antes:

import { parseISO, endOfDay } from "date-fns";

export default defineComponent({
  props: { timestamp: { type: "string" } },
  async run({ steps, $ }) {
    return endOfDay(parseISO(this.timestamp)).toISOString();
  },
});

Después:

const ts = $input.first().json.timestamp; // e.g. "2026-10-13T09:00:00.000Z"
const end = DateTime.fromISO(ts, { zone: "utc" }).endOf("day");
return [{ json: { endOfDay: end.toISO() } }]; // "2026-10-13T23:59:59.999Z"

date-fns calculaba endOfDay en la zona horaria local del servidor. En Luxon, indica la zona de forma explícita para que el resultado no dependa de la zona horaria configurada en la instancia de n8n.

formatInTimeZone(parseISO(start), tz, "H:mm") de date-fns-tz se convierte en DateTime.fromISO(start).setZone(tz).toFormat("H:mm"). El paquete moment básico funciona en n8n Cloud con require("moment"), pero moment-timezone no.

3. steps, $.export y valores de retorno

Pipedream pasa los resultados anteriores en steps. n8n lee los nodos anteriores con $('node name'), y un nodo Code debe devolver un array de items { json: {...} }.

Antes:

export default defineComponent({
  async run({ steps, $ }) {
    const { email } = steps.trigger.event.body;
    if (!email) return $.flow.exit("no email");
    $.export("domain", email.split("@")[1]);
    return { email };
  },
});

Después:

const { email } = $('trigger').first().json.body;
if (!email) return []; // no items: downstream nodes don't run, like $.flow.exit
return [{ json: { domain: email.split("@")[1], $return_value: { email } } }];

Luego, los nodos siguientes leen {{ $('validate').first().json.domain }} donde Pipedream usaba {{steps.validate.domain}}, suponiendo que el nodo se llama igual que el paso de Pipedream. Las props de código de Pipedream (this.firstName) no tienen un equivalente directo: escribe los valores directamente en el código, o léelos de un nodo Edit Fields colocado antes del nodo Code.

4. $.respond, esperas y suspensiones

En n8n, estas son funciones del workflow, no del código:

  • $.respond() se convierte en un nodo Respond to Webhook, con la opción Respond del nodo Webhook configurada como "Using 'Respond to Webhook' Node". Haz que el nodo Code devuelva el código de estado y el cuerpo, y luego úsalos en el nodo Respond to Webhook. Si el workflow termina sin llegar a ese nodo, n8n devuelve un mensaje estándar con código 200, mientras que Pipedream devolvía un 400 "No $.respond called in workflow."
  • $.flow.delay(ms) obliga a dividir el paso en dos, con un nodo Wait (After Time Interval) en medio.
  • $.flow.suspend() se convierte en un nodo Wait con Resume: On Webhook Call.

5. process.env y secretos

Antes: process.env.STRIPE_KEY. Después, elige una de estas opciones:

  • $vars.STRIPE_KEY. Las Variables de n8n son cadenas de solo lectura (valores de hasta 1000 caracteres) que se definen en la interfaz. Están disponibles en n8n Cloud Pro y Enterprise, y en self-hosted Business y Enterprise.
  • $env.STRIPE_KEY en n8n self-hosted. Desde n8n 2.0, N8N_BLOCK_ENV_ACCESS_IN_NODE vale true por defecto, así que esto solo funciona si lo cambias a false (cambios incompatibles de n8n 2.0).
  • Una credencial en un nodo HTTP Request. Suele ser el mejor lugar para las API keys, y la opción práctica en n8n Cloud Starter, que no incluye Variables.

6. Data stores

Un contador típico en Pipedream, con una prop de data store:

export default defineComponent({
  props: { db: { type: "data_store" } },
  async run({ steps, $ }) {
    const count = ((await this.db.get("count")) ?? 0) + 1;
    await this.db.set("count", count);
    return count;
  },
});

Lo mismo con los datos estáticos del workflow de n8n:

const store = $getWorkflowStaticData("global");
store.count = (store.count ?? 0) + 1;
return [{ json: { count: store.count } }];

Conoce las diferencias antes de depender de ellos:

  • Los datos estáticos solo se guardan cuando un workflow publicado se ejecuta desde un trigger o un webhook. Las ejecuciones de prueba manuales no los conservan.
  • Pertenecen a un solo workflow. Los data stores de Pipedream podían compartirse entre muchos workflows.
  • Según n8n, los datos estáticos "deberían ser pequeños", y no hay TTL como en set(key, value, { ttl }).
  • Solo funcionan en nodos Code de JavaScript, no en Python.

Para datos compartidos o más grandes, usa las Data Tables de n8n mediante el nodo Data Table (los nodos Code no pueden acceder a ellas directamente; el límite predeterminado es de 200 MiB por instancia), o una base de datos externa. En cualquier caso, los registros de los data stores no están en la exportación de Pipedream, así que cópialos antes del 30 de abril de 2027.

7. /tmp y File Stores

Pipedream le daba a cada ejecución un /tmp con permiso de escritura, y File Stores para guardar archivos por más tiempo. En n8n Cloud, el nodo Code no tiene acceso al sistema de archivos. Pasa los archivos entre nodos como datos binarios, usa los nodos Convert to File y Extract From File, o guárdalos en S3 o Google Drive. En n8n self-hosted puedes permitir fs con NODE_FUNCTION_ALLOW_BUILTIN o usar el nodo Read/Write Files from Disk. Descarga el contenido de los File Stores de Pipedream antes del cierre, porque no se exporta.

8. Pasos de código en Python

En n8n Cloud, el nodo Code de Python no puede importar ninguna biblioteca. En n8n 2.x self-hosted, Python se ejecuta de forma nativa en task runners: los imports solo funcionan si la imagen n8nio/runners incluye el paquete y este está en la lista de permitidos, el código lee _items o _item en lugar de pd.steps, y a los campos se accede con corchetes (item["json"]["email"]). El Python basado en Pyodide se eliminó en n8n 2.0. Si tus pasos de Python usan sobre todo requests, reescribirlos en JavaScript con this.helpers.httpRequest suele ser más rápido.

9. Self-hosted: habilita tus paquetes

Instala los módulos en tu imagen de n8n y luego habilítalos:

NODE_FUNCTION_ALLOW_BUILTIN=crypto,fs
NODE_FUNCTION_ALLOW_EXTERNAL=date-fns,lodash,stripe

La documentación de n8n aclara que, si tu instancia usa task runners, estas variables van en los task runners y no en el proceso principal de n8n. Convierte las sentencias import en require.

Cómo maneja Workflow Exit los pasos de código

El informe de migración gratuito lista cada paquete npm que importa cada paso de código y si n8n Cloud puede ejecutarlo, junto con las variables de entorno, los data stores, las llamadas a $.flow y las cuentas conectadas. Se ejecuta en tu navegador.

La conversión de pago transforma cada paso de Node.js en un nodo Code de n8n con una capa de compatibilidad encima de tu código original. La capa reconstruye steps, $.export, $.flow.exit, las props de this, los data stores (sobre los datos estáticos del workflow), las lecturas de process.env (un bloque de secretos al principio del nodo Code, o Variables de n8n en los planes de pago) y las llamadas al axios de @pipedream/platform, a axios y a node-fetch (sobre this.helpers.httpRequest). Se probó ejecutando workflows convertidos en n8n 2.x. Para los paquetes que n8n Cloud no puede cargar, una reescritura opcional con IA los reemplaza por funciones integradas de n8n o por llamadas HTTP. Los bloques Delay se convierten en nodos Wait. Una llamada a $.flow.delay o $.flow.suspend dentro del código obliga a dividir el paso alrededor de un nodo Wait, así que el informe marca esos pasos y hay que revisarlos después de la conversión. Las cuentas conectadas siguen necesitando credenciales de n8n, y el CHECKLIST.md generado las lista una por una.

Los planes empiezan en US$49 (hasta 25 workflows), y el primer workflow es gratis (precios). Para el proceso completo, consulta la guía para migrar de Pipedream a n8n, y para el panorama general, Pipedream vs n8n (en inglés). Si todavía no exportaste, empieza por exportar tus workflows y luego ejecuta el informe para ver cuántos de tus pasos chocan con estos límites.

Preguntas frecuentes

¿Puedo usar paquetes npm en el nodo Code de n8n Cloud?+

No. La documentación del nodo Code de n8n dice que en n8n Cloud no se pueden importar módulos npm externos. Hay dos módulos disponibles: el módulo crypto de Node.js y el paquete moment. n8n self-hosted puede habilitar otros módulos instalados con NODE_FUNCTION_ALLOW_EXTERNAL.

¿Funciona axios en un nodo Code de n8n?+

No en n8n Cloud, porque axios es un módulo externo. Usa this.helpers.httpRequest dentro del nodo Code, o un nodo HTTP Request. En n8n self-hosted puedes instalar axios y agregarlo a NODE_FUNCTION_ALLOW_EXTERNAL.

¿Qué reemplaza en n8n al process.env de Pipedream?+

Usa las Variables de n8n ($vars.NAME), disponibles en n8n Cloud Pro y Enterprise y en self-hosted Business y Enterprise. En n8n self-hosted también puedes usar $env.NAME, pero desde n8n 2.0 los nodos Code solo pueden leer variables de entorno si N8N_BLOCK_ENV_ACCESS_IN_NODE vale false.

¿Qué reemplaza en n8n a los data stores de Pipedream?+

Para un estado pequeño de un solo workflow, los datos estáticos del workflow, con $getWorkflowStaticData('global') en un nodo Code. Para datos compartidos entre workflows o tablas más grandes, las Data Tables de n8n mediante el nodo Data Table, o una base de datos externa. Los datos estáticos no tienen TTL y solo se guardan en las ejecuciones de producción.

¿n8n Cloud puede ejecutar mis pasos de código en Python de Pipedream?+

Solo si no importan nada. En n8n Cloud, el nodo Code de Python no puede importar ninguna biblioteca, ni siquiera la estándar. Reescribe esos pasos en JavaScript, o aloja n8n por tu cuenta y agrega los paquetes a la imagen del task runner.

¿Por qué mi código dice 'import and export may only appear at the top level' en n8n?+

El nodo Code de n8n no admite las sentencias import ni export. Los pasos de Pipedream usan export default defineComponent e import, así que quita el envoltorio, pon el cuerpo de run() en el nodo Code y carga los módulos permitidos con require.