An open-source CRM with a customisable data model: records, relations and views you shape yourself, hosted by them or on your own server.
Build me the CRM I actually need instead of a hosted Twenty: records, relations and views shaped to how I sell. Read this first: Twenty is open source and self-hosting it is a real answer — the fee buys upgrades and backups. The reason to build instead is narrow and honest: a CRM is a data model, and every generic one is somebody else's guess at yours. If your sales process has three stages and one custom field, a bespoke CRM is a weekend and it will fit perfectly. STACK - Node 20+ with Fastify, server-rendered HTML with a little vanilla JS - SQLite through better-sqlite3, WAL mode, with FTS5 - Caddy in front THE DATA MODEL - companies: id, name, domain, industry, size, address, notes_md, owner_id, created_at, archived_at - people: id, company_id, first_name, last_name, title, email, phone, linkedin_url, owner_id, created_at, archived_at - opportunities: id, company_id, name, stage, amount_cents, currency, probability, expected_close_on, closed_at, outcome, lost_reason, owner_id, source - stage_history: id, opportunity_id, from_stage, to_stage, at, actor_id — append-only, and where every honest sales metric comes from - activities: id, kind, subject, body, occurred_at, duration_ms, company_id, person_id, opportunity_id, actor_id, source — email, call, meeting, note, task - tasks: id, title, due_at, completed_at, assignee_id, related_kind, related_id - custom_fields and custom_values, for the handful of things that do not fit — but put the fields you know you need in the real tables as real columns, because a CRM built entirely out of custom fields is slow and impossible to query - views: id, entity, name, filters_json, sorts_json, visible_columns_json, group_by THE STAGE HISTORY, WHICH IS THE PART EVERY HOMEMADE CRM FORGETS - Storing only the current stage means you can never answer how long deals sit in each one, what your conversion is stage to stage, or whether this quarter is slower than last - So every stage change is a row, and every pipeline metric is computed from that series at query time - The same for amount: a deal whose value changed is two facts, not one, and the forecast should know which - None of it can be reconstructed later. Build it before the first real deal goes in FILLING IT IN WITHOUT DATA ENTRY - Mail sync, read-only, recording one activity per message with a known contact: address, direction, subject, timestamp and a short snippet. Never the body - Calendar sync, one activity per meeting with its attendees - Both incremental with a cursor, idempotent by external identifier - The last-contacted date is derived from activities and never typed. A CRM whose dates are maintained by hand is six weeks out of date within six weeks - Say plainly in the README what a mailbox sync stores, because that restraint is what makes it usable VIEWS AND PIPELINE - A table view with configurable columns, filters and sorting, saved as a view - A board view of opportunities by stage, with the total value per column - Drag to move a stage, which writes the history row - Every view is a saved query, never a copy THE FORECAST, HONESTLY - Weighted pipeline is the sum of amount times probability, and it is a weak number. Show it, and show the unweighted total beside it - Better: conversion rates computed from your own closed deals, by stage and by source, applied to what is open now. That is a forecast with evidence - Deals that have not moved in longer than your median stage duration, ranked. That list is worth more than any forecast - Lost reasons as a required field on a lost deal, which is the only way you ever learn anything from losing DEDUPLICATION - Candidates by exact email, by domain, by name similarity within a company - A review screen showing both records side by side; merging keeps every activity and is reversible - Never merge automatically. Two duplicates are an annoyance; a wrong merge is two customers' histories tangled together PERMISSIONS - Owner per record, with visibility rules: everyone, the owner's team, or the owner alone - Enforced in the query, default deny, including in search results SEARCH AND ESCAPE - FTS5 across companies, people, notes and activity subjects - Export everything as CSV and JSON in one command, including the stage history - Import from CSV with a mapping step and a dry run OPERATIONS - .env: DATABASE_PATH, BASE_URL, SESSION_SECRET, ENCRYPTION_KEY, HASH_SALT, IMAP_URL - Migrations on boot, each once - Mail credentials encrypted at rest - Nightly backup off the machine, restore script — this holds your customer relationships - Health endpoint reporting the age of the last mail and calendar sync WHAT MATTERS MOST Stage history and mail sync. Build the append-only history and the automatic activity recording first, then run one real quarter through it. A CRM that needs manual updating is abandoned by week three, and one without history can never tell you anything you did not already know. Give me the repository, migrations, .env.example, a seed pipeline with a quarter of history, and a README with deploy steps behind Caddy and the exact list of what a mailbox sync stores.
What you lose
- A managed instance with upgrades and backups, which is the whole difference between the free and paid versions
- A data model you can reshape without a migration, which is a serious piece of engineering
- Mail and calendar sync already written
If you would rather not build
- Postgres and four tables, which is what most teams need
What it costs
read from their page 15 Aug 2026
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $9/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
Why this verdict
our own opinion · changed only by a person
78/100
Verdict yes at 78 because the code is free — leaving the hosted plan is Docker. Four real tables beat a generic entity model for a long time.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about Twenty
answered from the record above
Is Twenty free?
No — the plan we track is $9 a month. Cloud from around $9 per user per month billed monthly; the software is free to self-host.
Can you replace Twenty by building your own?
YES. Replaceable in one session with an AI coding agent. Replacement score 78 out of 100, build time one session. Read what you lose before you decide.
How much does Twenty cost?
$9 a month on Cloud — $108 a year. Recorded 10 Aug 2026.
What do you lose by replacing Twenty?
A managed instance with upgrades and backups, which is the whole difference between the free and paid versions; A data model you can reshape without a migration, which is a serious piece of engineering; Mail and calendar sync already written. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Twenty?
Yes: Twenty, EspoCRM. 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

