Ep 07: Ditch the External DB — Mastering Native Data Tables for CRUD

⏱ Est. reading time: 10 min Updated on 4/9/2026

What Are Data Tables?

n8n 2.0's Data Tables is a built-in lightweight persistent store — think of it as a "workflow-dedicated simple database." No PostgreSQL, MongoDB, or Google Sheets setup required.

graph TB
    subgraph "Traditional (Complex)"
        W1[n8n Workflow] -->|"API call"| EXT[(External DB
PostgreSQL / Airtable)] end subgraph "Data Tables (Simple)" W2[n8n Workflow] -->|"Native node"| DT[(Built-in Data Tables
Zero config, zero latency)] end style DT fill:#22c55e,stroke:#16a34a,color:#fff style EXT fill:#ef4444,stroke:#dc2626,color:#fff

Use Cases

Scenario Example Traditional Data Tables
Deduplication Track processed email IDs Redis / file locks ✅ One table row
AI Prompt Mgmt Store system prompts per scenario Hardcoded / config files ✅ Table-driven
Simple CRM Track customer states Airtable / Sheets ✅ Native flow
Counters Daily ticket count PostgreSQL ✅ Auto-increment

CRUD Operations

Create

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Data Tables Node: Insert new record
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// Operation: "Insert"
// Table: "processed_emails"
// Columns:
//   email_id: {{ $json.messageId }}        ← Dynamic from upstream
//   processed_at: {{ $now.toISO() }}       ← Built-in current time
//   status: "completed"                     ← Static value

// Output includes auto-generated row ID:
// { "json": { "id": "row_abc123", "email_id": "msg_12345", ... } }

Read

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Data Tables Node: Query records
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// Method 1: Get all rows (with optional Limit)
// Method 2: Filter by condition — email_id = {{ $json.currentEmailId }}
// Method 3: Get single row by ID — Row ID: {{ $json.rowId }}

Update & Delete

// Update: Operation "Update Row" — must specify Row ID
// - Row ID: {{ $json.id }}
// - status: "failed", retry_count: {{ $json.retry_count + 1 }}

// Delete: Operation "Delete Row" — Row ID: {{ $json.id }}
// ⚠️ Irreversible! Consider soft-delete (update status to "deleted") instead

Practical: Email Deduplication Workflow

graph TB
    T[📧 Gmail Trigger] --> Extract[Set: Extract messageId]
    Extract --> Query[Data Tables: Query
email_id = messageId] Query --> Check{If: No results?} Check -->|"✅ New email"| Process[Process Content] Check -->|"❌ Already processed"| Skip[Skip] Process --> Record[Data Tables: Insert
Record processed ID] Record --> Notify[Slack: Notify] style Check fill:#f59e0b,stroke:#d97706 style Query fill:#22c55e,stroke:#16a34a,color:#fff

Next Episode

In Ep 08, we master n8n's workhorse for external communication — the HTTP Request node — covering authentication, pagination, and concurrency control.