Databases

Save to Database

Adds a row to a local SQLite database, creating the table and any missing column the first time it runs.

action.database_insert
DATABASESave to Database

At a glance

Takes
Any payload — its variables become the values you store
Emits
inserted, rowId, rowsAffected
Good for
Giving a flow a memory with no schema step

Set it up

Nothing has to exist first. Pick a database (or create one from the picker), type a table name that doesn't exist yet, and list the fields to store — each one a column name you invent and a value, either a literal or a {{variable}} from an earlier node. The first run creates the table, its columns and the row together.

The inspector for Save to Database: a table name and a list of fields.
The inspector for Save to Database: a table name and a list of fields.

Configure

FieldDefaultWhat it does
Database—Which database to write to. The picker fills in the id.
Table—The table to write to. It does not have to exist yet.
Fields—Each row is a column and the value to store in it.
Create the table if it doesn't existOnTurn it off once a table matters, so a typo in Table can't quietly start a second one.
On a conflicting rowStop with an errorSkip the row, or Replace the row, when the write collides with a unique index you added yourself.

A field's value is read one of two ways. A lone {{text}} keeps the upstream value's real type — a number stays a number. Anything else is a literal: 42 is an integer, 3.5 a real, true the integer 1, and "00123" in quotes is text, which is how a serial number keeps its leading zero. A mixed template like {{first}} {{last}} renders to text.

Output

Every key is available downstream as {{key}}.

KeyTypeValue
insertedBooleantrue when a row was written; false when a conflict rule skipped it
rowIdNumberThe managed id of the row just written, or null when nothing was. Store it to come back to that exact row
rowsAffectedNumberHow many rows were written. 0 is a normal answer when a conflict rule skipped the row

Example: store a note and confirm it

Input hands the flow some text. Save to Database writes it into a clips table that it creates on the first run. Notification reports the id it got back.

Three nodes: type something, store it, get told which row it became.
Three nodes: type something, store it, get told which row it became.

Paste this into the Flow Builder to get the same flow:

Take text from an Input trigger, save it to a clips table in my Clipboard History database, and notify me with the new row id.

Good to know

id and created_at are reserved. Every table this node makes gets both — an auto-numbering primary key and a UTC ISO-8601 stamp. A field with either name is refused; call it item_id instead.

A field that doesn't resolve is skipped, not blanked. If a value is exactly {{something}} and that variable isn't in the input, no column is created and no empty value is stored; the run log names what was skipped. If nothing resolves at all the node fails rather than writing a blank row.

A table auto-grows to 64 of your own columns (the managed pair doesn't count). Past that the node stops and points you at Run SQL, where you can shape a wide table deliberately.

SQLite has no boolean type. true is stored as 1 and reads back as the number 1, so match a flag with equals 1.

Replace the row deletes first. A node set to Replace is badged destructive: the colliding row is removed before the new one is written, and a database has no Trash.