A spreadsheet with a real relational model and Python formulas, aimed at people who outgrew a sheet but do not want a database project.
Build me the relational sheet I actually need instead of a hosted Grist: typed columns, real relations, formulas with a proper language, and access rules per row. Read this first: Grist is open source and self-hosting it is a real answer — the fee buys a hosted instance with backups, sharing and row-level access rules. Build this when you have one dataset that has outgrown a spreadsheet and you want it to be a real schema rather than a grid of guesses. STACK - Node 20+ with Fastify, server-rendered HTML with vanilla JS for the grid - SQLite through better-sqlite3, WAL mode. It is already a relational engine — use it as one - No client-side framework - Caddy in front THE DATA MODEL - tables: id, name, label, description - columns: id, table_id, key, label, kind, position, formula, is_formula, config_json, is_required, is_unique - Data rows live in real SQL tables with real columns and real constraints, created and altered by generated migrations. Not a key-value store — a generic store makes every constraint impossible and every query slow - references: a column of kind ref is a foreign key to another table's row id; reflist is a join table. Both are real - row_revisions: id, table_id, row_id, column_key, old_value, new_value, actor, at — append-only - views: id, table_id, kind, name, filters_json, sorts_json, group_by, visible_columns_json, linked_view_id - access_rules: id, table_id, column_key, role, permission, condition — the paid feature, and it belongs in the core COLUMN TYPES AND CONSTRAINTS - text, integer, decimal with precision, money with a currency, boolean, date, datetime with a zone, choice, choice list, reference, reference list, attachment, any - Each type has a parser, a validator, a formatter, a comparator, a filter set and a CSV form. Write that contract once - Constraints from the schema: required, unique, a check expression, and a foreign key that actually prevents an orphan - Type conversion is a migration with a dry run that reports the rows that would fail — never a silent coercion that turns a date into a number FORMULAS, WHICH IS THE REASON TO CHOOSE THIS - A real expression language rather than spreadsheet functions: variables, comparisons, conditionals, arithmetic, string and date operations, and aggregates over a reference list - Formulas reference other columns by name and referenced rows by dotted path — `client.name`, `sum(orders.total)` - Parsed into an AST and evaluated on read, with a dependency graph so a cycle is rejected at save time rather than found at render time - Errors shown in the cell with the reason, and a formula that fails on one row does not break the table - If you want Python-like power, implement a small safe interpreter over a fixed set of builtins, sandboxed with a time limit — never eval, and never anything that can reach the filesystem or the network VIEWS AND LINKING - Grid, card, chart and form - Linked views: select a row in one and the other filters to its related rows. This is the feature that makes a relational sheet feel different from a spreadsheet, and it is a filter parameter rather than anything clever - Filters composable, sorts on several columns, grouping with subtotals, hidden columns, frozen first column - Summary tables: a group-by with aggregates, computed at query time and never stored ACCESS RULES - Per table, per column, per row: a role and a condition over the row's own values or the user's attributes - 'A regional manager reads rows where region equals their own, and cannot see the salary column' - Enforced in the single query path on the server. A hidden column must be absent from the response, not hidden in the browser - Default deny, and a page generated from the rules showing what each role can do THE GRID - Keyboard first: arrows, Enter to edit, Escape to cancel, Tab to advance, copy and paste a rectangle including from a real spreadsheet - Virtualised so fifty thousand rows scroll - Undo and redo backed by the revision log - Validation errors on the cell IMPORT, EXPORT AND API - CSV and Excel import with a mapping step and a dry run that reports what would fail before anything is written - Export any view as CSV, and the whole document as SQLite — which it already is, and which is the cleanest escape hatch in this category - REST per table with filtering, pagination and the same access rules; tokens with scopes - Webhooks on change, signed and retried OPERATIONS - .env: DATABASE_PATH, STORAGE_PATH, BASE_URL, SESSION_SECRET, HASH_SALT - Migrations on boot, each once; a schema change through the interface writes a migration file - Nightly backup off the machine, restore script - Health endpoint WHAT MATTERS MOST Real columns and the formula dependency graph. Put the data in proper SQL tables with proper constraints from the first commit — that decision cannot be undone once there is data — and build the cycle detection before anybody writes a formula that refers to itself. Give me the repository, migrations, .env.example, a seed document of three related tables with formulas and access rules, and a README with deploy steps behind Caddy.
What you lose
- Python as the formula language, which is far more capable than spreadsheet functions
- A hosted instance with backups and sharing
- Access rules per row and per column on the paid tier
If you would rather not build
- A spreadsheet, if the data is genuinely flat
What it costs
read from their page 15 Aug 2026
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $8/mo | — | 15 Aug 2026 |
Their pricing page is where these came from. Seeing a different price? Tell us.
The escape hatch
open source · no votes, no paid placement
Grist
$0The product itself, free to self-host with documents as SQLite files.
gristlabs/grist-corefree · open source
Baserow
$0A no-code database with a friendlier grid and a plugin system.
baserow/baserowfree · open source
Why this verdict
our own opinion · changed only by a person
86/100
Verdict yes at 86. One container and a directory of SQLite files. Adding real types and relations on import is what makes the move worth doing.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about Grist
answered from the record above
Is Grist free?
No — the plan we track is $8 a month. Pro at around $8 per user per month billed monthly; the software is free to self-host.
Can you replace Grist by building your own?
YES. Replaceable in one session with an AI coding agent. Replacement score 86 out of 100, build time one session. Read what you lose before you decide.
How much does Grist cost?
$8 a month on Pro — $96 a year. Recorded 10 Aug 2026.
What do you lose by replacing Grist?
Python as the formula language, which is far more capable than spreadsheet functions; A hosted instance with backups and sharing; Access rules per row and per column on the paid tier. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Grist?
Yes: Grist, Baserow. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
Every week, something stops being worth paying for.
New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.
free forever · no tracking pixel · stored here, never passed to anyone

