Tables: formulas, import and export
How to compute with formulas in a Table, bring rows in from CSV or Excel, and take them out again, with the limits and rules that apply.
A Table is a channel type: one grid of typed columns and rows, with the channel's chat beside it. This guide is for people automating or migrating data. Everyday editing is in the app.
Before you start
- Plans. Tables are available on the Business plan: up to 100 Tables per org, 250,000 cells per Table (rows × columns), 365 days of row history and 100 shared views. A self-hosted server has every feature on.
- Who can do what.
- Anyone who can see the channel can see the Table and export it.
- Editing cells and rows, and importing, needs the channel's Table permission (on by default for every built-in role).
- Changing columns, setting a column's formula, and adding new columns during an import need the channel's Manage channel permission.
Formulas
A formula starts with = and is worked out on the server, so every viewer sees the same result. There are two kinds:
- A Formula column works out every row from one formula, including rows added later. Pick the Formula type when you add the column, or change it with Edit column. This is the normal way.
- A cell formula works out one cell: type text starting with
=into the cell.
References
| You write | It means |
|---|---|
[Hours]@row |
This row's Hours (the common case; the editor adds @row for you) |
Hours@row |
The same, for a column name without spaces |
[Hours]3 |
Hours in row 3. It follows the row if it moves, and shows #REF! if it's deleted. |
[Hours]:[Hours] |
The whole Hours column |
[Hours]1:[Hours]5 |
Rows 1 to 5 of Hours. [Hours]$1:[Hours]@row is a running total. |
[Task]:[Rate] |
Every column from Task to Rate, as a table for VLOOKUP or INDEX |
[Hours]@row:[Rate]@row |
This row, Hours through Rate |
@cell |
Inside a condition, the cell being tested: COUNTIF([Hours]:[Hours], @cell > 8) |
Formulas are stored by column and row identity, not by name, so renaming a column or moving a row never breaks one: the formula's text is shown with the new names.
Operators and values
Operators, lowest precedence first: comparisons = <> != < <= > >=, text join &, + -, * /, ^, % (50% is 0.5), and unary minus (-2^2 is 4, as in Excel). Text goes in "double quotes" ("" for a quote inside). TRUE, FALSE and error values such as #N/A can be written too.
- Numbers, text and checkboxes behave as in Excel:
"12" + 1is 13,TRUE * 5is 5, and a blank cell is 0 in a sum and""next to text. Text compares ignoring case. Numbers keep 15 significant digits, so0.1 + 0.2 = 0.3is TRUE. - Dates are counted in days:
[Due]@row + 7is a week later,[Due]@row - [Start]@rowis a number of days, and[Due]@row < "2026-11-03"compares as dates. TODAY()andNOW()use the workspace's day. They are worked out again once a day, shortly after midnight in the org's office time zone (Org settings → Office time zone; UTC when it isn't set).- Choices and people read as their labels:
[Status]@row = "Done". A multi-select reads as"Electrical, Urgent";HAS([Tags]@row, "Urgent"),COUNTMand conditions look at each choice. - Attachments read as how many there are.
- Where Tables follow Smartsheet rather than Excel:
IF(condition, value)with no third value leaves the cell blank;FINDandSEARCHgive 0 when nothing is found;VLOOKUPandMATCHare approximate unless you passFALSEor0.
Functions
The formula editor lists and autocompletes every function with its syntax. AVG is another name for AVERAGE, and RANK.EQ for RANKEQ.
| Group | Functions |
|---|---|
| Sums and counts | SUM, PRODUCT, AVERAGE, MEDIAN, MIN, MAX, LARGE, SMALL, RANKEQ, COUNT, COUNTA, COUNTBLANK, COUNTM |
| Conditional | COUNTIF, COUNTIFS, SUMIF, SUMIFS, AVERAGEIF, AVERAGEIFS |
| Rounding and maths | ROUND, ROUNDUP, ROUNDDOWN, MROUND, INT, TRUNC, CEILING, FLOOR, MOD, ABS, SIGN, SQRT, POWER, EXP, LN, LOG, LOG10, PI, ISEVEN, ISODD |
| Logic | IF, IFS, SWITCH, AND, OR, XOR, NOT, IFERROR |
| Checks | ISBLANK, ISNUMBER, ISTEXT, ISDATE, ISBOOLEAN, ISERROR, ISNA, NA |
| Text | CONCATENATE, CONCAT, JOIN, LEFT, RIGHT, MID, LEN, LOWER, UPPER, PROPER, TRIM, SUBSTITUTE, REPLACE, FIND, SEARCH, TEXT, VALUE, REPT, CHAR, UNICHAR, EXACT |
| Dates | TODAY, NOW, DATE, DATEONLY, YEAR, MONTH, DAY, WEEKDAY, WEEKNUMBER, YEARDAY, HOUR, MINUTE, DAYS, DATEDIF, EDATE, EOMONTH, NETDAYS, NETWORKDAYS, WORKDAY |
| Lookup | VLOOKUP, HLOOKUP, INDEX, MATCH, XLOOKUP, COLLECT, DISTINCT, CONTAINS, HAS |
| The Table | ROWNUMBER |
A few that are easy to miss:
COLLECT(range, range1, condition1, …)picks the cells whose rows meet the conditions; use it insideSUM,JOINorINDEX.DISTINCT(range)drops repeats.JOIN(range, [delimiter])joins a range's non-blank cells.TEXT(value, format)takes formats such as"0.00","#,##0","0%"and"yyyy-mm-dd".WEEKDAYcounts Sunday as 1;WEEKNUMBERis the ISO week.NETDAYSandNETWORKDAYScount both ends;NETWORKDAYSandWORKDAYcount Monday to Friday and take an optional list of holidays.
=IF([Due]@row < TODAY(), "Late", "")
=SUMIFS([Hours]:[Hours], [Owner]:[Owner], "Dana", [Status]:[Status], "Done")
=JOIN(COLLECT([Task]:[Task], [Status]:[Status], "Blocked"), ", ")
=NETWORKDAYS([Start]@row, [Due]@row)
Errors
| Shows | Means |
|---|---|
#DIV/0! |
Divided by zero or an empty cell |
#VALUE! |
The wrong kind of value (text where a number belongs, a range where one cell belongs) |
#REF! |
A column or row that doesn't exist (was it deleted?) |
#NAME? |
A function Tables doesn't have |
#N/A |
A lookup didn't find the value |
#NUM! |
A number out of range |
#CIRCULAR! |
The cell depends on itself through other formulas |
#BUDGET! |
The formula needs more work than one cell may use |
#ERROR! |
The text can't be read as a formula (the editor says where) |
When formulas recalculate
After every change, the formulas that read what changed are worked out again, and their new results arrive with the edit. In a very large Table, the first 5,000 formula cells are done at once and the rest follow within about 15 seconds.
Import from CSV or Excel
Choose Import CSV / XLSX on the Table's toolbar (on a computer or a phone). Rows are added at the end of the Table.
- Choose a
.csv,.tsvor.xlsxfile, or paste rows (copying from a spreadsheet works). For an Excel file, pick the Worksheet. - Say whether The first line is a header row.
- Check the preview. For each file column it shows what it Looks like (text, number, currency, percent, date, checkbox, dropdown, link or person) and where it Goes into: the column with the same name, a new column (if you manage the channel), or Don't import. People are matched by a member's email address, never by name.
- The first 50 rows are shown with every problem marked, and every row is checked, along with the size against your Table's cell limit. Problems block the import unless you tick Leave out rows with problems.
- Choose Import.
Undo
An import is one change. Undo import on the result screen, or Undo it next to "Last import" when you open the dialog again, removes its rows and any columns it added. The rows go to the Table's deleted rows for 30 days. The person who imported, or anyone who manages the channel, may undo.
Excel files
Only values are imported:
- Formulas come in as their last calculated results, never as working formulas. The dialog counts them, and a formula Excel never calculated comes in blank, so recalculate and save in Excel first. Rebuild formulas with Missived's column names afterwards.
- Dates become calendar days. Percentages, true/false and rich text (as plain text) come across. A merged cell keeps only its top-left value.
- Formatting, comments, images, hyperlinks, macros, row hierarchy and automations are not imported. Hidden rows and sheets in the file are imported like the rest, so remove anything you don't want shared.
Moving from Smartsheet: in Smartsheet, File → Export → Export to Microsoft Excel, then import the .xlsx and choose the data tab (not the comments or summary tabs).
Export
Export CSV and Export XLSX are on the same toolbar, for anyone who can see the Table. An export holds exactly the rows and columns you can see on the server. Your own sorting, filtering, hidden columns and widths in the browser are not applied; for a restricted export, publish a shared view.
- CSV: choice labels, people as email addresses, files as their names, ISO dates. It is the format the importer reads back. Text that a spreadsheet would run as a formula (starting with
=,+,-or@) gets a leading', and the importer removes it again. - XLSX: numbers, checkboxes and dates are real Excel values, percentages use percent formats, and column widths follow the Table. Formula results are exported as values. Text starting with
=stays text.
Shared views
A shared view publishes some of a Table's rows and columns as its own channel, for an outside party. Exporting from a view's channel gives only the view: its rows, its columns and its name, never the rest of the Table or any formula text. A withdrawn view can't be exported. Importing, undoing imports and row conversations belong to the Table itself, not to a view.
Row conversations
Choose 💬 on a row to open its thread. The first comment posts an anchor message in the channel's chat ("💬 Pull permits · row 14 in project-tracker") and your comment is its first reply, so mentions, notifications, search and reactions work as in any thread. The 💬 shows the reply count. Deleting the row keeps the conversation, and its card says the row was deleted.
What data moves
Nothing leaves Missived. Formulas are worked out on our servers, never by a third-party service. Imports are read on the server and the file itself isn't kept; exports go only to the person who downloads them. In an org that encrypts content, cell values, formulas and their results are encrypted at rest like messages. The org's audit log records imports, undone imports and exports with counts only, never the data.
Limits
| CSV | XLSX | |
|---|---|---|
| File size | 5 MB | 2 MB (20 MB once unpacked), and at most 5 MB of values |
| Rows per import | 10,000 | 10,000 |
| Columns | 100 | 100 |
| Other | 20 worksheets, 100,000 cells, 4,000 characters per cell, 15 seconds to read |
An Excel file over a limit is refused, never cut short: split it, or save it as CSV and import it in parts. Your Table's cell limit (250,000 on Business) applies too.
Troubleshooting
| Message | What to do |
|---|---|
| "Choose an XLSX up to 2 MB; split larger workbooks or use CSV." | Keep only the data tab, split the workbook, or use Save As → CSV UTF-8 in Excel. |
| "Workbook took too long to read." | Split it or use CSV. |
| "Only people who manage this channel can add columns" | Map every file column to an existing one, or skip it. |
| A column is locked | Only people who manage the channel can import into it. |
| A person column doesn't match | People are matched by the email of an org member; check the addresses. |
Tables API
Read and write a Table's rows over the REST API with an API token (Settings → Developer, or an app's token). Everything below is in the API reference under Tables.
| Scope | Lets a token |
|---|---|
tables:read |
list Tables, read columns and rows, find rows, export CSV / XLSX |
tables:write |
add, change, upsert and delete rows |
What a token reaches is what its owner reaches in the app. A person's token sees the Tables they can open (a guest's, only the Tables in their workspaces) and edits where they can edit. An app's token sees only Tables and shared views in channels the app was added to. Through a shared view a token gets the view and nothing else: its columns, its rows, its rules for adding and deleting — never the Table behind it. Columns and settings are not changed through the API.
Find a Table
GET /v1/orgs/{orgId}/tables
GET /v1/tables/{tableId}
Each Table comes with its columns: id, name, type, writable, and a select column's choices. A shared view has its own id and kind: "view"; use it like any Table id.
Read rows
GET /v1/tables/{tableId}/rows?limit=50&cursor=…
GET /v1/tables/{tableId}/rows?column=Email&[email protected]
GET /v1/tables/{tableId}/rows/{rowId}
A row carries its values twice: cells keyed by column id (stable across renames) and fields keyed by column name. Values are plain JSON — text, numbers, true / false, dates as YYYY-MM-DD, a choice's label, people as { id, name, email } (no email for an app), files as { id, file_name, download_url }, a formula's result (never its formula). column + equals finds rows the way an upsert matches its key: text ignores case and surrounding spaces, and "12" equals 12 in a number column.
Every row has a version. Send it back as If-Match: "<version>" when you change the row, and the change is refused with 409 row_changed if one of the cells you send changed in the meantime.
Write rows
POST /v1/tables/{tableId}/rows { "cells": { "Name": "Paint", "Due": "2026-11-02" } }
PATCH /v1/tables/{tableId}/rows/{rowId} { "cells": { "Status": "Done" } }
PUT /v1/tables/{tableId}/rows?key=Email { "cells": { "Email": "[email protected]", "Plan": "Pro" } }
DELETE /v1/tables/{tableId}/rows/{rowId}
Name a column by id or by name. A cell you leave out is left alone; null clears it. Values can be the JSON shapes above or text the column reads — "1,250", "45%", "yes", "1h 30m", a choice's label, a person's email (people's tokens). Columns the Table fills in (formulas, created by, auto numbers) can't be written.
Upsert (PUT …?key=) finds the one row whose key column equals the value you send and sets the other cells — only those that differ — or adds the row when there is none. It runs with the Table locked, so two upserts of the same new key add one row, not two. If more than one row already has that key, the answer is 409 conflict. The answer says created: true or false (and X-Upsert: created / updated).
POST and PUT take an Idempotency-Key, so a retried request adds nothing twice. Writes go through the same path as an edit in the grid: formulas recalculate, open grids update live, change notifications go out, and the row's history says the change came through the API. They count against the same per-person editing budget as the grid (a 429 says when to try again).
Export
GET /v1/tables/{tableId}/export.csv
GET /v1/tables/{tableId}/export.xlsx
What the token sees, written as the app's exports write it. An app's export names people instead of giving their email addresses.
Events
sheet.row_created, sheet.row_updated (with changed_columns) and sheet.row_deleted go to event subscriptions, the bot gateway (intent tables) and Zapier, Make and n8n. An event carries the Table (id, name, kind, channel_id), the row's id and version and who changed it; the values (row.cells, row.fields) come along only when the org sends content in events — otherwise read the row back. A shared view's events go only to a subscription that names the view's channel, or a bot added to it, and carry only what the view shows. A batch that touches more than 200 rows (a large import) sends the first 200; read the rest back with the API.
Limits
Up to 200 rows a page. Rows, columns and cells are capped by your plan as in the app.