How to Import a CSV into a monday.com Board Automatically
Turn CSV files into monday.com items without the manual import: pick up a CSV from SFTP, email or your File Store, map its columns to board columns, and create or update items on a schedule.
What This Integration Does
monday.com can import a spreadsheet by hand, but recurring files (a daily order export, a weekly lead list from an event platform, a supplier's delivery schedule) need someone to repeat the import every time, and repeat imports create duplicates. This Spojit workflow automates it. It fetches the CSV, parses it, matches each row to an existing item by a key column (an order number, an email, a reference), updates the item if it exists and creates it if not, and moves the file to a "processed" folder so it is never imported twice.
Matching on a key makes the import safe to repeat: running the same file again updates the same items rather than adding copies. Each row is processed on its own, so one bad row is reported without stopping the rest.
Prerequisites
- A Monday.com connection in Spojit (personal API token).
- A board with a column that holds the unique key (for example a text column
Order number), and the column IDs for every column you will fill (use theget-boardtool). - Where the CSV comes from: an FTP / SFTP connection, a mailbox address for the Mailhook trigger, or your Spojit File Store.
Step 1: Trigger
Pick the trigger that matches how the file arrives:
- Schedule (for example
0 * * * *) when a system drops the file on SFTP. - Mailhook when the file is emailed: send it to the workflow's generated address, and read the CSV attachment with an Attachment node.
Step 2: Fetch the File
For SFTP, add an FTP / SFTP step with list-directory on the inbound folder, then a Loop over the .csv files with download-file for each. Name the downloaded content file.
Step 3: Parse the CSV
Add a CSV Tools step with parse, header on, so each row becomes an object keyed by the CSV's header names. If the file uses semicolons or tabs, set the delimiter. Use CSV Tools dedupe on the key column if the file can contain the same record twice. Name the output rows.
Header names such as Order number or Due date contain spaces, which are awkward in templates. Rename them to snake_case in a short Code Runner step (execute-javascript, input set to the parsed rows) and use the new names from here on:
return data.map(r => ({
order_number: r["Order number"], customer: r["Customer"], status: r["Status"],
due_date: r["Due date"], amount: r["Amount"], email: r["Email"]
}));
The renamed rows are in that step's result.
Step 4: Find Existing Items
Add a Monday.com step with raw-graphql that returns the board's items with the key column, using monday.com's items_page_by_column_values query (or list-items and a lookup for small boards). Build a map from key to item ID in a Code Runner step, then return each row with its itemId when one exists:
const byKey = new Map(data.items.map(i => [i.key, i.id]));
return data.rows.map(r => ({ ...r, itemId: byKey.get(r.order_number) ?? null }));
Step 5: Create or Update Each Row
Add a Loop in ForEach mode over the rows, with On iteration error set to Continue with the next item, and a Condition on {{ item.itemId }}:
- New: Monday.com
create-itemwith the item name from the CSV (for example{{ item.customer }}) and the column values. - Existing: Monday.com
update-itemwithitemId{{ item.itemId }}and the column values.
Column values use monday.com's formats, keyed by column ID:
{
"text_order": "{{ item.order_number }}",
"status": { "label": "{{ item.status }}" },
"date4": { "date": "{{ item.due_date }}" },
"numbers": "{{ item.amount }}",
"email": { "email": "{{ item.email }}", "text": "{{ item.email }}" }
}
Step 6: Move the File and Report
After the rows, add an FTP / SFTP step with rename to move the file from /inbound/ to /processed/, so the next run does not import it again. Post a summary to Slack: rows created, updated and failed, with the keys of failed rows.
Tips
- Dates: monday.com date columns expect
YYYY-MM-DD. Convert other formats with the Date & Timeparseandformattools before writing. - Groups: to put new items in a specific group, pass the group ID when creating (the
raw-graphqltool'screate_itemmutation takesgroup_id). - Messy files: if column names change between files, an Agent Mode step can map whatever headers arrive to your board's columns and return them in a Response Schema.
- Big files: monday.com's API has a complexity budget per minute. For thousands of rows, process in chunks and spread runs out.
Common Pitfalls
- Status labels that do not exist: writing a label the status column does not have fails the row. Map CSV values to your existing labels, or create the labels first.
- Headers that change: if the source system renames or reorders a column, the snake_case Transform stops matching and fields arrive empty. Check the header row when a supplier changes their export.
- Numbers with symbols: number columns reject
$1,250.00. Strip currency symbols and thousands separators first. - Re-importing the same file: without moving processed files, an hourly schedule re-reads the same CSV every hour. Matching on the key prevents duplicates, but moving the file avoids wasted runs.
Testing
Put a CSV with three rows on the SFTP server, one of which matches an existing item's key. Run the workflow manually: two items should be created, one updated, and the file moved to the processed folder. Run it again with the same file in the inbound folder to confirm nothing is duplicated.