Najpierw pojawia się Google Sheets — szybko, znajomo, działa. Potem Airtable albo Notion. Potem ktoś pyta o RODO i okazuje się, że dane klientów siedzą na serwerach w USA.
Od wersji 1.x n8n rozwiązuje ten problem we własnym zakresie: przez Data Tables.
To wbudowana, strukturyzowana baza danych bezpośrednio w środowisku n8n — bez zewnętrznych integracji, bez dodatkowego API i bez stawiania osobnej infrastruktury.
W tym artykule przejdziemy przez:
- czym są Data Tables,
- kiedy zastępują Google Sheets,
- jak wykonać podstawowe operacje CRUD,
- jak użyć Data Tables z agentem AI,
- kiedy lepiej przejść na zewnętrzną bazę danych.
Pokażę też dwa praktyczne workflowy z projektów klientów: AI asystenta zakupowego i asystenta ofertowego.
Film
n8n Data Tables — nowa funkcja, która zmieni wszystko
Czym są Data Tables i gdzie je znaleźć?
Data Tables to relacyjna baza danych wbudowana bezpośrednio w n8n.
Możesz myśleć o niej jak o uproszczonym Google Sheets, ale z kilkoma ważnymi różnicami:
- dane są przechowywane w Twoim środowisku n8n,
- nie musisz konfigurować zewnętrznej integracji,
- nie potrzebujesz OAuth ani osobnych credentials,
- typowanie kolumn jest egzekwowane po stronie n8n,
- workflowy mają natywny dostęp do danych przez węzły n8n.
Data Tables znajdziesz w menu głównym n8n, w zakładce Data Tables, obok Workflows.
Jeśli nie widzisz tej zakładki, sprawdź wersję n8n.
Tworzenie tabeli
Kliknij New Table, podaj nazwę tabeli i zdefiniuj kolumny.
Dostępne typy danych:
| Typ | Zastosowanie |
|---|---|
string | Tekst, nazwy, adresy, opisy |
number | Liczby całkowite i dziesiętne, ceny |
boolean | Flagi true/false, status aktywny/nieaktywny |
datetime | Daty i godziny zdarzeń |
Dwie kolumny tworzą się automatycznie i nie możesz ich usunąć:
created— czas utworzenia rekordu,updated— czas ostatniej modyfikacji.
To przydatne przy audytach, raportach i debugowaniu workflow.
Data Tables vs Google Sheets
| Aspekt | Data Tables | Google Sheets |
|---|---|---|
| Lokalizacja danych | Twoje środowisko n8n | Serwery Google |
| RODO / compliance | Większa kontrola przy self-hosted n8n | Wymaga osobnej oceny i konfiguracji |
| Konfiguracja | Natywna w n8n | OAuth, credentials |
| Limity API | Brak dodatkowej integracji API | Limity po stronie Google API |
| Typowanie | Egzekwowane | Brak ścisłego typowania |
| Formularze / UI | Brak | Google Forms |
| Eksport do CSV | Ręcznie | Natywny |
Najkrócej: jeśli potrzebujesz prostej tabeli do workflow i nie chcesz wystawiać danych poza środowisko automatyzacji, Data Tables są wygodnym wyborem.
Jeśli potrzebujesz formularzy, współdzielenia arkuszy z użytkownikami biznesowymi albo zaawansowanego ręcznego edytowania danych, Google Sheets nadal może być prostsze.
CRUD — operacje krok po kroku
Węzeł Data Table w n8n obsługuje pięć głównych operacji:
- Insert Row — dodawanie rekordów,
- Get Rows — pobieranie rekordów,
- Update Row — aktualizacja rekordów,
- Delete Row — usuwanie rekordów,
- Row Exists — sprawdzanie, czy rekord istnieje.
Insert Row — dodawanie rekordów
JavaScript1 2 3 4Węzeł: Data Table Operacja: Insert Row Tabela: [nazwa tabeli] Pola: [mapowanie pól z poprzednich węzłów]
Przykład mapowania dla tabeli z listą zakupów:
JSON1 2 3 4 5{ "name": "{{ $json.productName }}", "quantity": "{{ $json.qty }}", "price": "{{ $json.unitPrice }}" }
Get Rows — pobieranie rekordów z filtrami
Najbardziej elastyczna operacja. Możesz pobierać:
- wszystkie rekordy,
- rekordy spełniające warunki, np.
price > 3.50, - rekordy z limitem, np.
Limit: 10, - wszystkie rekordy przez
Return All: true.
Warunki można łączyć z logiką:
- Must match ALL conditions — odpowiednik SQL
AND, - Must match ANY condition — odpowiednik SQL
OR.
Przykład: pobierz droższe produkty w dużych ilościach.
JavaScript1 2 3Warunek 1: price > 3.50 Warunek 2: quantity >= 3 Łączenie: Must match ALL conditions
Update Row — aktualizacja rekordów
JavaScript1 2 3 4 5Węzeł: Data Table Operacja: Update Row Tabela: [nazwa tabeli] Warunek identyfikacji: [np. name = "chleb"] Pola do aktualizacji: [nowe wartości]
Uwaga: Update Row wymaga podania warunku identyfikującego wiersz. Jeśli nie podasz warunku, węzeł nie wykona operacji.
To ważne szczególnie wtedy, gdy Data Table jest narzędziem dla agenta AI.
Delete Row — usuwanie rekordów
Podobnie jak Update — wymaga warunku identyfikującego wiersz do usunięcia.
JavaScript1Warunek: name = "{{ $json.productToDelete }}"
Row Exists — sprawdzanie istnienia
Zwraca true albo false.
Przydaje się przed:
- Insert Row — żeby nie dublować rekordów,
- Update Row — żeby nie zwracać błędu na nieistniejący wiersz.
Przykład 1 — AI asystent zakupowy
Pierwszy przykład to klasyczna lista zakupów obsługiwana przez agenta AI.
Użytkownik rozmawia z botem w języku naturalnym:
- „dodaj chleb za 5 zł",
- „usuń szczypiorek",
- „co mam na liście?".
Agent rozpoznaje intencję i wykonuje odpowiednią operację na Data Table.
Struktura tabeli shopping_list
| Kolumna | Typ | Opis |
|---|---|---|
name | string | Nazwa produktu |
quantity | number | Ilość |
price | number | Cena jednostkowa |
created | datetime | Auto |
updated | datetime | Auto |
Architektura workflow
JavaScript1 2 3 4 5 6Chat Trigger └── AI Agent (GPT-4.1 mini) ├── Narzędzie: get_rows ├── Narzędzie: insert_row ├── Narzędzie: update_row └── Narzędzie: delete_row
Węzeł AI Agent obsługuje całą logikę. Sam decyduje, które narzędzie wywołać na podstawie intencji użytkownika.
Konfiguracja narzędzi agenta
Każde narzędzie to węzeł Data Table podłączony jako tool do AI Agent.
Opis narzędzia jest kluczowy, bo model podejmuje decyzję na jego podstawie.
Narzędzie: get_rows
JavaScript1 2 3 4 5Opis: "Pobierz produkty z listy zakupów. Wywołaj, gdy użytkownik pyta o zawartość listy." Tabela: shopping_list Operacja: Get Rows Warunki: brak Return All: true
Narzędzie: insert_row
JavaScript1 2 3 4Opis: "Dodaj nowy produkt do listy zakupów. Model wypełnia pola name, quantity i price." Tabela: shopping_list Operacja: Insert Row Pola: name, quantity, price
Narzędzie: delete_row
JavaScript1 2 3 4Opis: "Usuń produkt z listy zakupów na podstawie nazwy." Tabela: shopping_list Operacja: Delete Row Warunek: name = {given_name}
Narzędzie: update_row
Tu pojawia się nieoczywisty problem.
Bez precyzyjnego opisu agent może nie wiedzieć, jak budować warunek do aktualizacji. W testach próbował różnych formatów i potrafił się mylić.
JavaScript1 2 3 4 5 6 7 8Opis: "Zaktualizuj ilość lub cenę produktu na liście zakupów. Budowanie warunku: ustaw pole 'name' jako wartość podaną przez użytkownika. Przykład: jeśli użytkownik mówi 'zmień cenę chleba na 6 zł', warunek to name = 'chleb', pole price = 6." Tabela: shopping_list Operacja: Update Row Warunek identyfikacji: name = {given_name}
Im bardziej nieoczywista operacja, szczególnie z parametrami, tym bardziej precyzyjny powinien być opis narzędzia.
Test asystenta
JavaScript1 2 3 4 5 6 7 8 9 10 11 12 13 14Użytkownik: Jakie produkty masz na liście? Agent: [wywołuje get_rows] Na liście masz: pomidory (2 szt., 3,50 zł) i szczypiorek (1 pęczek, 2,00 zł). Użytkownik: Dodaj chleb za 5 zł. Agent: [wywołuje insert_row z name="chleb", price=5] Dodałem chleb (5 zł) do listy zakupów. Użytkownik: Usuń chleb. Agent: [wywołuje delete_row z warunkiem name="chleb"] Chleb został usunięty z listy.
Więcej o budowaniu agentów z własną bazą wiedzy znajdziesz w artykule o agencie AI na własnych danych z n8n i Gemini.
Przykład 2 — asystent ofertowy z dwiema tabelami
Drugi przykład pochodzi z projektu dla firmy produkującej odzież z nadrukami.
Klient wybiera produkt, np. bluzę, t-shirt albo czapkę, i opisuje wykończenie: nadruk, haft, napis. System ma wygenerować spersonalizowaną ofertę handlową z ceną netto i brutto.
Struktura tabel
Tabela products
| Kolumna | Typ | Przykładowe wartości |
|---|---|---|
name | string | „bluza biała", „t-shirt czarny" |
price | number | 199, 89, 149 |
Tabela extras
| Kolumna | Typ | Przykładowe wartości |
|---|---|---|
name | string | „nadruk", „haft", „napis" |
price | number | 35, 45, 25 |
Architektura workflow
JavaScript1 2 3 4 5 6 7 8Form Trigger └── Get Row (products, WHERE name = {formularz.nazwa}) └── IF (czy produkt istnieje?) ├── NIE → Stop + "Produkt nie znaleziony" └── TAK → Get All Rows (extras) └── Code (JS: mapowanie danych) └── AI Agent / LLM └── Oferta handlowa
Krok 1 — Form Trigger
Formularz n8n ma dwa pola:
nazwa_produktu— text, np. nazwa produktu,opis_wykonczenia— textarea, np. „biały napis z logo firmy".
Krok 2 — Get Row z products
JavaScript1 2 3 4 5Węzeł: Data Table Operacja: Get Rows Tabela: products Warunek: name = {{ $json.nazwa_produktu }} Limit: 1
Krok 3 — IF: sprawdź, czy produkt istnieje
JavaScript1 2 3Warunek: {{ $json.name }} istnieje (not empty) Gałąź TRUE → kontynuuj Gałąź FALSE → Stop z komunikatem "Produkt nie znaleziony"
Krok 4 — Get All Rows z extras
JavaScript1 2 3 4Węzeł: Data Table Operacja: Get Rows Tabela: extras Return All: true
Pobieramy wszystkie dodatki. Model LLM sam zdecyduje, które pasują do opisu klienta.
Krok 5 — Code w JavaScript
Ten węzeł zbiera dane z obu tabel i tworzy ustrukturyzowany obiekt dla LLM.
JavaScript1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23const product = $('Get Row products').item.json; const extras = $('Get All Rows extras').all().map(i => i.json); const opis = $('Form Trigger').item.json.opis_wykonczenia; // Dopasuj pasujące dodatki na podstawie opisu. // Prosty matching — LLM dopasuje kontekstowo. const selectedExtras = extras; const basePrice = product.price; const extrasTotal = selectedExtras.reduce((sum, e) => sum + e.price, 0); const totalNet = basePrice + extrasTotal; const totalGross = totalNet * 1.23; // VAT 23% return [{ json: { product: product.name, base_price: basePrice, opis_wykonczenia: opis, available_extras: selectedExtras, total_net: totalNet, total_gross: parseFloat(totalGross.toFixed(2)) } }];
Krok 6 — LLM generuje ofertę
Węzeł OpenAI albo dowolny LLM z system promptem:
JavaScript1 2 3 4 5 6 7 8 9 10 11 12 13 14Jesteś asystentem sprzedażowym firmy produkującej odzież z nadrukami. Na podstawie poniższych danych wygeneruj profesjonalną ofertę handlową. Wybierz TYLKO te dodatki z listy, które pasują do opisu wykończenia klienta. Policz cenę końcową na podstawie ceny bazowej + wybranych dodatków. Dane: {{ JSON.stringify($json) }} Format odpowiedzi: - Produkt bazowy i cena - Lista wybranych dodatków z cenami - Cena netto i brutto (VAT 23%) - Krótki opis oferty dla klienta
Wynik
JavaScript1 2 3 4 5 6 7 8Produkt: Biała bluza — 199 zł Wykończenie: Napis z logo — 25 zł ───────────────────────── Cena netto: 224,00 zł Cena brutto: 275,52 zł (VAT 23%) Oferta obejmuje białą bluzę z profesjonalnie wykonanym napisem. Realizacja: 7–10 dni roboczych.
Kiedy używać Data Tables, a kiedy zewnętrznej bazy?
| Scenariusz | Data Tables | Zewnętrzna baza |
|---|---|---|
| Lista zakupów, prosta baza klientów | Tak | Zbędna |
| Katalog produktów < 10 000 rekordów | Tak | Opcjonalnie |
| Integracja z zewnętrznym systemem CRM | Nie | Wymagana |
| Zapytania SQL z JOIN-ami | Nie | Wymagana |
| > 100 000 rekordów z wyszukiwaniem pełnotekstowym | Nie | Wymagana |
| RODO: dane PII muszą zostać on-premise | Tak, przy self-hosted n8n | Tylko on-premise DB |
| Raportowanie z BI tools, np. Power BI albo Metabase | Nie | Wymagana |
| Agent AI z małą bazą wiedzy | Tak | Zbędna |
Data Tables świetnie sprawdzają się jako szybki start, gdy chcesz zbudować prototyp bez konfigurowania PostgreSQL ani MongoDB.
Przy rosnącej skali, bardziej złożonych zapytaniach i integracji z narzędziami BI warto migrować do dedykowanej bazy.
Jeśli Twój agent ma przeszukiwać tysiące dokumentów, a nie dziesiątki rekordów, sprawdź artykuł o RAG chatbocie z n8n i Qdrant.
Dalej w tym klastrze
-
Agent AI na własnych danych bez RAG — n8n i Gemini z Google Drive
Jak wkleić własne dokumenty do kontekstu agenta bez wektorowej bazy. -
RAG chatbot z n8n i Qdrant
Gdy dane rosną powyżej możliwości Data Tables i okna kontekstowego.
Chcesz wdrożyć agenta AI w swoich procesach?
Jeśli chcesz wdrożyć agenta AI obsługującego procesy sprzedażowe lub operacyjne, umów spotkanie z Kacprem. Pokażemy, jakie rozwiązanie będzie optymalne dla Twojej skali.
