Twój workflow ma 40 node'ów. Nikt nie wie co robi. Debugowanie trwa godziny. Zmiana jednej rzeczy psuje trzy inne. Brzmi znajomo? Sub-workflows i Code node to rozwiązanie – modularność, reusability i custom logic, które zamieniają spaghetti w inżynierię.
TL;DR
- Sub-workflow – osobny workflow wywoływany jak funkcja (parametry → wynik)
- Execute Workflow node – wywołuje sub-workflow z głównego workflow
- Code node – JavaScript lub Python bezpośrednio w n8n (pełna kontrola)
- Kiedy co: sub-workflow = reusable logika, Code node = transformacje danych
- Zasada: workflow z >20 node'ów → rozważ rozbicie na sub-workflows
Nie masz n8n? Zainstaluj w 15 minut. Kontekst: kompletny poradnik n8n.
Sub-workflows – modularność
Co to jest
Sub-workflow to osobny workflow, który wywołujesz z innego workflow – jak funkcja w programowaniu. Wysyłasz parametry, dostajesz wynik.
Kiedy używać
- Ta sama logika w wielu workflow – zamiast kopiować 5 node'ów do 10 workflow, stwórz sub-workflow i wywołuj go
- Workflow >20 node'ów – rozbij na mniejsze, czytelne moduły
- Zespół – różne osoby odpowiadają za różne sub-workflows
- Testowanie – testujesz sub-workflow niezależnie od reszty
Jak to działa
1. Stwórz sub-workflow
Nowy workflow → dodaj Execute Workflow Trigger (to trigger dla sub-workflow).
Przykład: sub-workflow „Send Notification":
Execute Workflow Trigger → IF (channel = slack)
→ Slack (wyślij wiadomość)
→ IF (channel = email)
→ Gmail (wyślij email)
2. Wywołaj z głównego workflow
W głównym workflow dodaj node Execute Workflow:
- Workflow: wybierz sub-workflow „Send Notification"
- Data: przekaż parametry:
{
"channel": "slack",
"message": "Nowy lead!",
"recipient": "#leads"
}
3. Odbierz wynik
Sub-workflow może zwrócić dane (przez Return node lub ostatni node w chain). Główny workflow otrzymuje je jako output Execute Workflow node.
Wzorce sub-workflows
1. Notification Hub
Jeden sub-workflow obsługuje WSZYSTKIE powiadomienia (Slack, email, SMS, push). Główne workflow wywołują go z parametrami channel i message.
Main workflow → Execute Workflow ("Notify")
→ Notify: Switch na channel → Slack / Gmail / Twilio
2. Data Enrichment
Sub-workflow wzbogaca dane o kontakcie – szuka w LinkedIn, Clearbit, Google.
Main workflow → Execute Workflow ("Enrich Contact")
→ Enrich: HTTP Request (Clearbit) + HTTP Request (LinkedIn) → Merge → Return
3. Error Reporter
Sub-workflow loguje błąd i wysyła alert. Wywoływany z Error Workflow.
Error Workflow → Execute Workflow ("Log Error")
→ Log Error: Google Sheets (log) + Slack (alert) → Return
Nazewnictwo sub-workflows: prefix [SUB] – np. [SUB] Send Notification, [SUB] Enrich Contact. Od razu widać co jest modułem, a co głównym workflow.
Code node – pełna kontrola
Nie wszystko da się zrobić klikając. Czasami potrzebujesz pętli, regex, custom formatowania, obliczeń. Code node daje Ci JavaScript (lub Python) bezpośrednio w workflow.
Tryby
1. Run Once for All Items – kod wykonuje się raz, masz dostęp do wszystkich itemów:
const items = $input.all();
const total = items.reduce((sum, item) => sum + item.json.amount, 0);
const avg = total / items.length;
return [{ json: { total, avg, count: items.length } }];
2. Run Once for Each Item – kod wykonuje się osobno dla każdego itemu:
const name = $input.item.json.name;
const email = $input.item.json.email;
return {
json: {
name: name.trim(),
email: email.toLowerCase(),
domain: email.split('@')[1],
initials: name.split(' ').map(n => n[0]).join('').toUpperCase()
}
};
Kiedy Code node
| Zadanie | Bez Code | Z Code |
|---|---|---|
| Prosty mapping pól | Edit Fields | Nie potrzebny |
| Regex (wyciągnij numer faktury) | Nie da się | text.match(/FV\/\d+\/\d+/)?.[0] |
| Deduplikacja po emailu | Nie da się (prosto) | [...new Map(items.map(i => [i.json.email, i])).values()] |
| Obliczenia (suma, średnia, top N) | Nie da się (prosto) | Standard JS |
| Formatowanie daty (polskie) | Ograniczone | date.toLocaleDateString('pl-PL') |
| Parsowanie HTML/XML | Nie da się | cheerio / regex |
| Custom walidacja | IF (ograniczona) | Pełna logika |
Przykłady praktyczne
Deduplikacja listy po emailu:
const items = $input.all();
const seen = new Set();
const unique = [];
for (const item of items) {
const email = item.json.email?.toLowerCase();
if (email && !seen.has(email)) {
seen.add(email);
unique.push(item);
}
}
return unique;
Wyciągnij numer faktury z tekstu:
const text = $input.item.json.email_body;
const match = text.match(/(?:FV|FA|FAKT)[\/\-]?\s*(\d+[\/\-]\d+[\/\-]?\d*)/i);
return {
json: {
...($input.item.json),
invoice_number: match ? match[0] : 'NOT_FOUND'
}
};
Grupowanie itemów po kategorii:
const items = $input.all();
const groups = {};
for (const item of items) {
const cat = item.json.category || 'other';
if (!groups[cat]) groups[cat] = [];
groups[cat].push(item.json);
}
return Object.entries(groups).map(([category, items]) => ({
json: { category, count: items.length, items }
}));
Code node to potężne narzędzie, ale każdy Code node to miejsce, które trzeba debugować ręcznie. Nie pisz w Code tego, co da się zrobić node'ami (Edit Fields, IF, Switch). Code = ostatnia deska ratunku, nie pierwszy wybór.
Python w Code node
n8n obsługuje Python w Code node (od wersji 1.x). Przydatne gdy:
- Znasz Python lepiej niż JavaScript
- Potrzebujesz bibliotek ML (pandas, numpy – ograniczone w sandboxie)
- Parsowanie danych (Python jest wygodniejszy do data wrangling)
items = _input.all()
total = sum(item.json['amount'] for item in items)
return [{"json": {"total": total, "count": len(items)}}]
Python w n8n działa w sandboxie – nie masz dostępu do pip install. Dostępne są podstawowe moduły. Dla zaawansowanych potrzeb (ML, scraping) – użyj HTTP Request do zewnętrznego API.
Debugging workflow
Executions log
Każde uruchomienie workflow jest zapisywane w Executions. Kliknij execution → widzisz dane w każdym node'ie (input/output).
Test workflow
Kliknij Test workflow – uruchomi się raz, zobaczysz dane w każdym node'ie w czasie rzeczywistym. Najlepszy sposób na debugging.
Console.log w Code node
console.log('Debug:', JSON.stringify($input.item.json));
// Widoczne w execution data
Typowe pułapki
- Brakujące dane – node zwraca
undefinedbo pole ma inną nazwę niż myślisz. Sprawdź Input w execution. - Typy –
"123"(string) vs123(number). Code node:parseInt()/Number(). - Puste tablice – workflow zatrzymuje się gdy node zwraca 0 itemów. Dodaj „Always Output Data" w settings.
- Expression vs Code – expressions n8n (
{{ }}) to nie JavaScript. W Code node piszesz czysty JS.
Best practices
1. Konwencja nazewnictwa
- Główne workflow:
Lead Capture Pipeline - Sub-workflows:
[SUB] Send Notification - Sticky Notes: opis sekcji workflow (kto, co, dlaczego)
2. Sticky Notes jako dokumentacja
Dodaj Sticky Notes z opisem sekcji workflow:
SEKCJA: Walidacja danych
- Sprawdza czy email jest poprawny
- Sprawdza czy firma istnieje w CRM
- Odrzuca spam (AI klasyfikacja)
3. Minimalizuj Code node
Code node = kod do utrzymania. Im mniej kodu, tym mniej bugów. Zanim napiszesz Code – sprawdź czy nie ma node'a, który to robi.
4. Wersjonowanie
n8n nie ma wbudowanego Git. Workaround:
- Regularny eksport workflow (JSON) → Git repo
- Nazwy workflow z wersją:
Lead Pipeline v2.3 - Tagi w n8n do organizacji
Więcej o stabilności na produkcji: n8n Error Handling.
FAQ
Czy sub-workflow spowalnia workflow?
Minimalnie – wywołanie sub-workflow to ~50-100ms overhead. Dla typowych workflow to nieistotne. Nie optymalizuj przedwcześnie – czytelność > kilkadziesiąt milisekund.
Ile sub-workflows mogę mieć?
Bez limitu na self-hosted. Praktycznie: typowy projekt ma 3-10 sub-workflows. Więcej = overengineering.
Czy Code node obsługuje npm packages?
Nie natywnie – Code node działa w sandboxie. Masz dostęp do wbudowanych modułów (crypto, url, querystring). Dla zewnętrznych bibliotek – użyj HTTP Request do API lub rozszerzenia n8n (custom node).
Python czy JavaScript w Code node?
JavaScript: domyślny, lepsze wsparcie, szybszy. Python: wygodniejszy do data processing. Wybierz ten, który znasz lepiej.
