# Store data with Data Tables

> Use n8n Data Tables to keep lists, logs and lookup values inside n8n, and to stop workflows from processing the same item twice.

Source: https://viralistic.nl/help/n8n/data-tables

Workflows often need to remember something: which emails they already handled, a list of customers, a set of prompts, or a log of AI decisions. Data Tables give you simple tables inside n8n for exactly that, without setting up a spreadsheet or database. This article shows when to use them and the patterns that come up most.

## When to use Data Tables

Good uses:

- **Remember what you processed**, so a workflow never handles the same item twice.
- **Lookup lists**, such as product codes, team members or routing rules.
- **Logs**, such as every AI classification with its input, for later review.
- **Shared settings or prompt texts** that several workflows read.
- **Small datasets** collected by forms or webhooks.

Use something else when people outside n8n need to edit the data every day (a spreadsheet or CRM is friendlier), or when you store large volumes (use a real database).

> **Note:** Data Tables are for light to moderate storage. By default, all data tables in an instance share a total limit of 200 MiB. n8n warns you as you approach it, and writes fail once you reach it. Self-hosted instances can raise the limit.

## Create a table

1. Open your project overview and go to the **Data tables** tab.
2. Create a data table and give it a clear name, such as `Processed emails`.
3. Start **from scratch**, or **import a CSV** to create the columns and rows in one go.
4. Add columns. Each column has a type: String, Number, Boolean or Date.

You can add, edit and delete rows by hand in this view, and download the table as CSV from its menu.

## Use a table in a workflow

Add the **Data Table** node. With the resource set to **Row**, the main operations are:

| Operation             | What it does                                              |
| --------------------- | --------------------------------------------------------- |
| Insert                | Adds a new row                                            |
| Get                   | Finds rows that match your conditions                     |
| Update                | Changes rows that match your conditions                   |
| Upsert                | Updates a matching row, or inserts one if none exists     |
| Delete                | Removes matching rows                                     |
| If Row Exists         | Passes on only the items that already have a matching row |
| If Row Does Not Exist | Passes on only the items that have no matching row yet    |

When you insert, you can **Map Automatically** if your field names match the column names exactly, or **Map Each Column Manually**.

## Pattern: never process the same item twice

This is the most common use. Say a schedule checks an inbox or API every 10 minutes and may see the same message again.

```text
Trigger  →  Data Table: If Row Does Not Exist  →  Process  →  Data Table: Insert
```

1. Create a table `Processed items` with a String column `itemId` and a Date column `processedAt`.
2. After the trigger, add a Data Table node with **If Row Does Not Exist**. Match the column `itemId` against the ID of the incoming item, such as an email message ID or order number.
3. Do the real work on the items that pass.
4. At the end, **Insert** a row with the `itemId` and `processedAt` set to `{{ $now.toISO() }}`.

Put the insert at the very end. If the processing fails halfway, the item is not marked as done and will be tried again next time.

## Pattern: lookup table

Keep routing rules out of your workflow logic. For example, a table `Routing` with columns `category` and `slackChannel`. After an AI step classifies a request, a **Get** on `category` returns the right channel. To change the routing, you edit a row instead of the workflow.

## Pattern: AI decision log

Insert one row per AI decision with the input, the output and a timestamp. Review it weekly. It shows where the model gets things wrong and gives you real examples to improve your prompt.

## Good to know

- Data tables belong to a project. Everyone in that project can use them.
- You cannot read data tables directly from a Code node. Use the Data Table node.
- Claude can create data tables and add rows through the n8n MCP server. See [Use the n8n MCP server](https://viralistic.nl/help/n8n/n8n-mcp).
- Self-hosted backups include data tables, because they live in the n8n database. See [Update and back up a self-hosted n8n](https://viralistic.nl/help/n8n/self-hosting-maintenance).

> **Tip:** Add a Date column to every table you write to from a workflow. It makes debugging and clean-up much easier later.

## Next steps

- [Build your first workflow](https://viralistic.nl/help/n8n/first-workflow)
- [Run workflows on a schedule](https://viralistic.nl/help/n8n/schedules)
- [Error handling and alerts](https://viralistic.nl/help/n8n/error-handling)
