Nodes/ComfyDL/Dataset → Write DB
ComfyUI Node

Dataset → Write DB

It drops and recreates your table every single run

By Cynthia-lxx·Created 3 months ago·Updated 13 days ago· 7
Dataset → Write DB
  • dataset
  • db_path
◄db_pathdataset_out.db►
◄tabledata►

What it is

ComfyDL is Cynthia-lxx's d2l-derived pack for doing deep learning inside ComfyUI, with a universal DATASET type (features, optional labels, column names) moving between readers, adapters, trainers and writers. Dataset → Write DB writes a dataset into a SQLite table.

It's the grown-up alternative to a CSV file in the same way Read DB → Dataset is the grown-up alternative to reading one: the table is typed, queryable, and - unlike the CSV's no-versioning-at-all situation - at least explicitly replaceable. If you're stashing training sets you'll query back later, or converting a messy workbook into something you can WHERE against, this is the node.

How it works

After materialising the dataset with to_dataframe(), it builds a SQLAlchemy engine and streams the frame in:

engine = create_engine(f"sqlite:///{db_path}")
df.to_sql(table, engine, if_exists="replace", index=False, chunksize=1000)

Three things in that line decide how the node behaves.

if_exists="replace" means it drops the table and recreates it on every execution. This is not an append node. Re-running the graph wipes the table and rewrites it - which is fine, arguably ideal, for a regeneratable dataset, and genuinely dangerous if you assumed you were accumulating rows. Because the drop is scoped to that one table name, other tables in the same database file are untouched.

chunksize=1000 means rows go in 1,000 at a time, so a large dataset isn't double-buffered in memory the way the CSV writer's single to_csv call is. This is the writer to pick for something big.

index=False means pandas' row numbers aren't stored as a column. Combine that with the fact that the dropped-and-recreated table has no primary key, and you get a plain data table - good for reading back, not for incremental updates.

Like its sibling Read DB → Dataset, this is SQLite only: the URL is hard-coded to sqlite:///, with no widget for a connection string. The database file is created if it doesn't exist.

Inputs and outputs

Required: dataset (a forced input socket), db_path (STRING, default dataset_out.db) and table (STRING, default data - the same default name the DB reader's SELECT * FROM data expects, so those two nodes are meant to pair).

Output: db_path, a STRING for chaining. Note the output is the path, not the table name, so if you wire it into another node you're passing along the file, not the query target.

Install

Manager → search ComfyDL, or:

cd ComfyUI/custom_nodes
git clone https://github.com/Cynthia-lxx/ComfyDL
pip install -r ./ComfyDL/requirements.txt

Restart. The pack's requirements are only matplotlib, IPython and matplotlib-inline; pandas and SQLAlchemy both come from your existing ComfyUI environment (SQLAlchemy is a ComfyUI dependency, so it's nearly always there), while pandas sometimes isn't - pip install pandas if the readers or writers complain. And because the pack loads node modules inside a try/except that prints [ComfyDL] Warning: Failed to load <module>, a dependency problem reads as "the node isn't in the menu."

Where people get burned

The replace-on-every-run behaviour. If you're running a graph repeatedly hoping to build up a table, you'll end up with exactly the last run's rows. Want accumulation? Do the appending in a real SQL tool, or write timestamped files instead.

Path formatting inside the URL. sqlite:/// plus your path, with forward slashes for Windows drives (sqlite:///D:/data/out.db). Relative paths resolve against ComfyUI's working directory, and a typo'd folder creates a fresh, empty database rather than failing loudly - then Read DB → Dataset tells you there's no such table.

Table names are interpolated, not escaped by you. Keep them plain identifiers (data, train_v2) rather than names with spaces or punctuation.

No dtype guarantees. SQLite is dynamically typed, so a float32 feature column lands as whatever SQLAlchemy maps it to. Round-tripping through this table may subtly change types, which is fine for numbers and annoying if you were relying on exact reproducibility.

NaNs go in as NULLs and come back as NaN - the same NaN that will poison a training loss downstream. Clean the data before it leaves the graph.

Categoryd2l/Datasets

Inputs (3)

NameTypeDefaultDescription
datasetDATASET—
db_pathSTRINGdataset_out.db—
tableSTRINGdata—

Outputs (1)

NameTypeDescription
db_pathSTRING—