All nodes/Data/DataFrame I/O
Write CSV
Writes a DataFrame to a CSV file in the connected file_store. Overwrites the target file if it exists.
Type in the graph: df_write_csv
Exec
An error branch can be enabled (expose_error_output) to handle failures on their own path.
Ports can be split into separate execution and data handles.
Try it
Minimal working workflow
- Execute + Data
Runs as pasted
When to use it
Saves a table as a CSV file in the store. The neighbouring File Write writes text and can replace individual lines; here the text is assembled for you out of the table — delimiter, encoding, header row — and the file is always replaced whole.
Pick CSV when a machine will read the file or move it into another system. If a person will open it in Excel, look at Write XLSX instead: no encoding or delimiter questions there.
How it works
The “DataFrame” port carries both the trigger and the data — the node has no separate execution input. If another branch should decide the moment of writing, enable “Split input ports” and you get separate legs for execution and value.
The input takes more than a table: a list of objects (JSON records) and CSV text are parsed by the node itself, so a converter before the write is not always needed.
The path is a template: reports/{{ variables.session_id }}.csv gives one file per session.
The output is path, bytes_written and rows_written (data rows, header excluded).
Common mistakes
- Expecting an append. There is no append mode: every run replaces the file. History is made with a path carrying a date or a session id.
- The WebDAV folder does not exist. The workspace store creates missing folders itself,
WebDAV does not: writing
reports/2026/x.csvfails until the directory exists. - Cyrillic or emoji in cp1251. A character the encoding cannot carry fails the step at encode time, and retrying does not help. For a file people will double-click in Excel, choose “UTF-8 with BOM”.
- An empty table. An empty result is not an error: you get a file with the header alone and
rows_written: 0. If an empty report is meaningless, check for it earlier in the graph.
Inputs
| Port | Wire | Payload | Notes |
|---|---|---|---|
DataFramedf | Execute + Dataexecute_data | dataframe | |
File storefile_store | Datadata | — | shown when connection_source ≠ "auto" |
Outputs
| Port | Wire | Payload | Notes |
|---|---|---|---|
Successoutput | Execute + Dataexecute_data | object | |
Erroron_error | Execute + Dataexecute_data | — | shown when expose_error_output = true |
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
File pathpath | string | "" | Path relative to the store root. Jinja templates are rendered per run, so ``reports/{{ variables.session_id }}.csv`` writes one file per session. supports templates |
Delimiterdelimiter | string | , | Column separator, usually ``,`` or ``;``. |
Text encodingencoding | string | utf-8 | Character encoding of the file. Use utf-8-sig when the CSV must open cleanly in Excel, cp1251 for legacy Cyrillic exports. Options: |
Include header rowinclude_header | boolean | true | Write the column names as the first row. |
Connection sourceconnection_source | string | auto | Where this node gets its connection. 'From the run context' uses what the platform already knows (the Telegram bot this workflow is deployed to / this workspace's own file store) and needs no wiring. 'External connection' shows the resource port so a config node can be wired into it. Options: |
Subfolderstore_subfolder | string | "" | Optional folder inside this workspace's store to treat as the root, e.g. `reports` or `sessions/{{ variables.session_id }}`. Blank = the store root. supports templates shown when connection_source = auto |
| Advanced | |||
Max bytesmax_bytes | integer | 52428800 | Refuse to transfer more than this many bytes. |
Shared fields
Every node has these three — the platform adds them, not the node author.
expose_error_output— When enabled, show an execution output to connect nodes that run if this step fails.split_ports_in— Show separate execution and data input handles instead of one combined port.split_ports_out— Show separate execution and data output handles instead of one combined port.