CRM migration guide

The Definitive Guide to Migrating to Twenty CRM

Twenty CRM is an open-source, modern CRM whose migration model rewards teams that pre-create custom fields, learn its metadata-driven data model, and choose between self-host and Twenty Cloud before the first CSV is uploaded.

21 min read 9 sections Updated May 27, 2026
Twenty CRM
Contacts
Companies
Deals
Leads
Activities
Notes

Inside this guide

What you'll learn, section by section

  1. 01

    Why teams migrate to Twenty CRM

    The four shapes a Twenty CRM migration takes, and what makes the platform easier — or harder — than the category average.

  2. 02

    The Twenty CRM data model you need to map into

    Standard objects, custom objects via metadata UI, junction relations, and the upsert keys you'll wire on every field — the destination schema decoded.

  3. 03

    Pre-migration prep — the work before you touch Twenty CRM

    What must be true on the source, the destination, and across the team before the first row hits the import wizard.

  4. 04

    Import mechanisms: CSV wizard and direct database access

    Two paths in, each with different limits and shapes. Picking the wrong one is how a Twenty migration stalls at scale.

  5. 05

    Mapping your data into Twenty CRM

    The longest section — because field mapping is where almost every Twenty migration that fails actually breaks.

  6. 06

    The pitfalls that derail Twenty CRM migrations

    Failure modes ranked by impact, each tied to the exact Twenty mechanism that breaks.

  7. 07

    Validation and cutover

    What to verify after the import job, in what order — and how to fail safely when something is wrong.

  8. 08

    Migration partners and tools

    Implementation partners, iPaaS vendors, and specialist migration shops — what each is good for and how to choose.

  9. 09

    Frequently asked questions

    The questions every Twenty CRM migration team works through before they sign the scope.

Section 01

Why teams migrate to Twenty CRM

The four shapes a Twenty CRM migration takes, and what makes the platform easier — or harder — than the category average.

Twenty was founded by Charles Bochet and Félix Malfait, launched publicly through Y Combinator (S23), and ships under an AGPL-3.0 licence with a self-hostable codebase on GitHub 112. The team positions Twenty as a modern, open-source alternative to Salesforce and HubSpot — built from a clean slate in TypeScript, NestJS, React and PostgreSQL.

The typical Twenty customer is a developer-led startup, a SaaS company, or a small-to-mid-market team — 5 to 100 users — that wants Salesforce-depth customisation without the licensing cost, or a team replacing Zoho or HubSpot to escape contact-tier billing and vendor lock-in. Compared with Salesforce, Twenty positions on no governor limits, no per-seat licence and a metadata-driven data model that lets you build custom objects the same way the platform builds standard ones.

The shapes of migration that actually land on Twenty tend to fall into four patterns. First, Salesforce or HubSpot exits, driven by total cost of ownership and a desire for data ownership — practitioners cite $9/user Cloud or $0 licensing for self-host versus $25–$165/user/month on legacy CRMs. Second, Zoho consolidations, where a small team has hit reliability or customisation limits and wants a cleaner data model 28.

Third, homegrown or vibe-coded CRM replacements — teams that built something in Lovable, Airtable or Notion and have outgrown it, but still want full control over the schema 29. Fourth, self-hosted CRM moves from EspoCRM, SuiteCRM or Dolibarr when a team wants a modern stack (React, Postgres) over PHP.

Each shape has a different difficulty profile: a Zoho migration usually has clean object parity but messy custom-field labels, while a Salesforce migration drags Apex, Flows and validation rules that do not move across at all.

What makes migrating *to* Twenty easier than the category average is its data model. Custom objects use the same treatment as standard ones — there is no Enterprise gate and no extra licence. Self-host gives you direct PostgreSQL access for power-user bulk imports, which is a path most managed CRMs simply do not offer 38.

What makes it harder than the average is that Twenty is still an actively evolving project. The People and Companies standard objects ship with a narrower set of pre-built fields than HubSpot or Salesforce, which means every new workspace spends 30 to 60 minutes creating basic fields before the first import 41.

The CSV import path was capped at 2,000 rows in early 2025 and was raised to 10,000 in later releases — the limit is moving, but it is still much tighter than the row caps you may be used to on HubSpot or Salesforce 68.

Views, workflows and permissions do not import — they are rebuilt manually after the data lands 12. Teams that scope for that rebuild work up front finish on time; teams that assume parity with Salesforce or HubSpot do not.

Twenty's open data model removes lock-in; what it does not remove is the rebuild work for views, workflows and sequences.

Section 02

The Twenty CRM data model you need to map into

Standard objects, custom objects via metadata UI, junction relations, and the upsert keys you'll wire on every field — the destination schema decoded.

Twenty platform Contacts Companies Deals Tickets Tasks Notes
Standard objects orbit the platform; every association can be many-to-many with optional labels.

Twenty's CRM is built around a small set of standard objects plus an unrestricted custom-object layer driven from metadata tables 36. Workspaces are the multi-tenant boundary — every object, field and record lives inside a workspace, and one Twenty deployment can host many.

Before you can map a field on the source side, you need to know exactly which destination object the row belongs on, what fields it requires, and which value will serve as its upsert key. The table below summarises the standard objects in a Twenty workspace and the additional ones you typically end up creating.

Object Stores Required on import Tier
People Individuals — contacts, leads, partners Name (first/last); email recommended as unique key Standard, all deployments
Companies Organisations associated with people and opportunities Name; domain recommended as unique key Standard, all deployments
Opportunities Deals in a sales pipeline Name, stage, company or contact association Standard, all deployments
Notes Free-form notes attached to people, companies, opportunities Title or body, target record association Standard, all deployments
Tasks To-dos and action items linked to records Title, due date optional, assignee Standard, all deployments
Workspace Members Users in the workspace; referenced as owners/assignees Email; must exist before import to bind ownership Standard; provision before data
Custom Objects Anything else — Projects, Subscriptions, Volunteers, Listings Define in Settings → Data Model before importing records Unlimited; same treatment as standard
Junction Objects Many-to-many connectors between two objects Enable Junction Relations in Settings → Updates → Lab Standard, all deployments [42]

People can use email as the unique identifier — Workspace Members are also addressable by email, which is how you bind ownership during a CSV import 3. Companies are most reliably matched on domain in the format https://acme.com (Twenty stores the full URL form and rejects acme.com or www.acme.com as not matching) 3.

Opportunities, custom objects and any other object without a natural key should use Twenty's internal id (UUID) as the upsert key. You can either let Twenty assign IDs and store them back in the source, or generate UUIDs in the source and pass them in. Re-importing a CSV with previously defined IDs is supported but has known edge cases when columns are omitted 33. Plan the unique-key strategy on day one.

Once you import, Twenty validates each row against the field schema before committing — errors highlight in yellow in the UI and you can fix them inline before the import is confirmed 22. Custom field types determine validation and storage; the catalogue below covers what you can model and the limits you need to plan around.

Field type Limits Notes
Text / Long Text Postgres text (effectively unbounded) Long Text used for multi-line; no native rich-text yet 33
Number Integer or decimal Currency is a separate type carrying a currency code
Date / Date & Time ISO-8601 Date & Time required for activity timestamps
Select (single) User-defined options Imports must use internal option names, not display labels 322
Multi-Select User-defined options Multiple values per cell; round-trip caveat on overwrite 14
Email / Phone / Domain / Links Composite types — primary + additional Use Email for People; Domain for Companies
Relation Many-to-one or one-to-many Reference parent by id or unique field (email/domain) 3
JSON Postgres JSONB Structured data store; not formula-aware
Rating / Boolean / Currency 1–5 / true-false / decimal+code Boolean must import as TRUE/FALSE uppercase 3
Computed / Formula Not yet supported Open feature request — rebuild as workflow or app-side logic 11

Relationships in Twenty are modelled as relation fields on the object. Many-to-many is supported via a junction object pattern — you create an intermediate object (for example, Project Assignment) with two many-to-one relations, then enable the Junction Relations lab toggle to render linked records directly instead of the intermediate row 42.

There is no native master-detail cascade-delete: deleting a parent does not automatically delete children. If your source platform relied on cascade semantics, reproduce them in a Twenty workflow on the parent's Deleted event, or rely on the underlying Postgres foreign-key behaviour when self-hosting with a custom schema.

Section 03

Pre-migration prep — the work before you touch Twenty CRM

What must be true on the source, the destination, and across the team before the first row hits the import wizard.

The single best predictor of a clean Twenty migration is how much work you do on the source side before the first import button is pressed. Twenty's own documentation frames migration as 'an opportunity for a fresh start — don't bring over clutter' 12, and the import wizard is unforgiving about fields that do not yet exist on the destination object.

Fields must exist before import. Uploading a CSV creates records but does not create fields.

— Twenty Documentation

Treat the source export as raw material that needs to be shaped to Twenty's expected formats — email lowercased, phone normalised to E.164 with country codes, domains rewritten to the https://acme.com form, select values converted to internal option names, dates rewritten to ISO-8601, booleans uppercased to TRUE/FALSE 3.

Source-side prep

  • Audit and dedup the source database before export. Twenty does not ship pre-built dedup tooling outside of a manual Merge Records action introduced in 1.3.0, so duplicates landing during import become a manual cleanup task.
  • Decide what to leave behind — outdated contacts with no activity in 2+ years, unused custom fields, test data, opt-outs. Twenty's docs explicitly recommend pruning before migration 12.
  • Normalise emails to lowercase and trim whitespace. Email is the natural unique key for People and Workspace Members.
  • Rewrite domains to the canonical https://domain.com form. Twenty stores domains with the URL prefix and will not match domain.com or www.domain.com 3.
  • Convert select-field display labels to internal option names for every dropdown — pipeline stages, status fields, custom enumerations. Enable Advanced Mode in Twenty Settings to see the internal name for each option 2226.
  • Generate or preserve a stable external ID — either keep the source platform's primary key in a custom field, or pre-allocate UUIDs that will become Twenty's id on import.

Destination-side prep

  • Decide self-host vs. Twenty Cloud before you provision. Self-host runs on Docker Compose with PostgreSQL and Redis, needs at least 2 vCPU and 4 GB RAM, and gives you direct database access. Cloud (app.twenty.com) bills at $9/user/month and removes the infrastructure burden.
  • Stand up a test workspace as a sandbox. Twenty's free tier and self-host model make this trivial: spin up a parallel instance, dry-run the import, validate, then re-run against the production workspace.
  • Invite users before importing data. Twenty's docs are emphatic — if your import references owners or assignees by email, those users must exist in the workspace first, otherwise relations cannot be mapped 83.
  • Pre-create every custom object and custom field under Settings → Data Model. The CSV import creates records, never fields — uploading a column for a non-existent field returns an unmapped column error 38.
  • Configure select-field options with the internal option names you plan to use in your source-side transformation, not the human display labels.

People prep

Cutover only works if humans cooperate. Lock down a source-system freeze window — typically 24 to 72 hours — and communicate it to every department that touches the CRM. Train sales reps on Twenty's table and Kanban views, the Command Menu (the ⋮ icon used to trigger imports), and the workflow rebuild plan.

A typical small-team Twenty migration runs one to two business days end-to-end; a 50,000-record consolidation with custom objects and historical activities runs one to two weeks of elapsed time. Build the human runway accordingly.

Section 04

Import mechanisms: CSV wizard and direct database access

Two paths in, each with different limits and shapes. Picking the wrong one is how a Twenty migration stalls at scale.

Twenty exposes load paths whose right choice depends on dataset size, object mix, and whether you need to re-run idempotently. The CSV import wizard covers most one-shot migrations under 50,000 records. Direct PostgreSQL access on self-host adds a path for power users prepared to bypass the application layer entirely 38.

CSV import wizard

The native import lives in the Command Menu — open the object's table view, click the icon top right, then Import records 18. Supported formats are CSV (recommended), XLSX and the legacy XLS 13. Each file must contain only one object type — People in one file, Companies in another, Opportunities in a third 18.

Steps: download the template to confirm column names, upload the CSV, map columns to Twenty fields, review errors highlighted in yellow and fix them inline in the UI, then confirm the import 22. Pre-import validation runs *before* the records are written, so you can correct a malformed boolean or an unrecognised select value without polluting the workspace 22.

Limits: 10,000 records per file in current releases, up from the original 2,000-row cap 68. Twenty's documentation recommends splitting 10,000–50,000-record loads into multiple files 38151.

Direct PostgreSQL (self-host only)

Self-hosted Twenty exposes its underlying Postgres database. For power-user bulk imports — hundreds of thousands of records, custom-object loads with complex relations, or migrations where you want SQL-level transactional control — connecting directly to the database and writing rows is the fastest path 38. The trade-off: you bypass Twenty's validation layer, the Metadata schema mapping, and the application-side change events, so workflows will not fire for inserts done this way.

Rule

Under 2,000 records → CSV wizard. 2,000–10,000 → single CSV file. 10,000–50,000 → split CSVs. Self-host plus 100k+ rows → direct Postgres after a sandbox dry run.

Section 05

Mapping your data into Twenty CRM

The longest section — because field mapping is where almost every Twenty migration that fails actually breaks.

SOURCE TWENTY CRM FirstName, LastName firstname, lastname AccountName company AnnualRevenue annualrevenue Owner.Email hubspot_owner_id CreatedDate createdate
Field-mapping flow — every source field resolves to a destination property or an explicit drop.

Mapping is where every migration earns its scars. The schema decisions you make in your mapping spreadsheet determine whether Kanban views work on day two, whether workflows fire correctly on day five, and whether your team trusts the data on day thirty.

Work object by object, top to bottom of the import order specified in Twenty's own documentation: Companies first (no dependencies), then People (depend on Companies), then Opportunities (depend on Companies and People), then Notes and Tasks (depend on the records they attach to), then Custom Objects 83151.

Companies

Common source → Twenty Company mapping

Source Destination
  • account_name / company_name
    name

    Required

  • website / domain
    domainName

    Format strictly as https://acme.com — not acme.com or www.acme.com 3

  • industry
    industry (or custom Select field)

    Map source labels to Twenty internal option names; create the field first

  • annual_revenue
    annualRecurringRevenue (Currency)

    Strip currency symbols; provide value plus currencyCode (USD/EUR)

  • employees
    employees (Number)

    Integer; strip commas

  • owner / account_owner
    accountOwnerId (relation to Workspace Members)

    Map by user email; the user must exist in Twenty first 83

People

Common source → Twenty People mapping

Source Destination
  • first_name / last_name
    name.firstName / name.lastName

    Composite Name field; supply both sub-keys

  • email
    emails.primaryEmail

    Lowercased; recommended unique key

  • phone
    phones.primaryPhoneNumber + primaryPhoneCountryCode

    Normalise to E.164 before import

  • job_title
    jobTitle

    Single-line text

  • company / organisation
    companyId (relation)

    Use companyDomain cross-reference (https://acme.com) on the People CSV 83

  • linkedin / twitter URLs
    linkedinLink / xLink (Links)

    Composite type — primary URL plus optional label

  • owner
    createdBy / pointOfContact relation

    Use user email; pre-provision users 83

Opportunities and pipelines

Recreate every pipeline-equivalent stage in Twenty before importing Opportunities. Twenty currently models pipeline as the stage Select field on the Opportunity object — Kanban view groups records by stage 153. Multiple pipelines on one object (record types in Salesforce parlance) are an open community request, not native today 153, so teams consolidating multiple source pipelines typically either: (a) keep them as separate Select options on a single Opportunity object, or (b) create one custom object per pipeline for full isolation.

Common source → Twenty Opportunity mapping

Source Destination
  • opportunity_name / deal_name
    name

    Required

  • stage / pipeline_stage
    stage (Select)

    Use internal option name, not display label; create option first 22

  • amount
    amount (Currency)

    Provide amountMicros + currencyCode (USD, EUR)

  • close_date
    closeDate

    ISO-8601 date

  • primary_contact
    pointOfContactId (relation to People)

    Cross-reference by email or id

  • account / company
    companyId (relation to Companies)

    Cross-reference by domainName (https://acme.com) or id

  • owner
    Workspace Member relation

    Map by user email; pre-provision

Custom-field mapping strategy

Resist the urge to map every source custom field one-to-one. Migrate only the custom fields used by an active process, view or report in the last 12 months. Twenty's documentation explicitly endorses this: 'don't bring over clutter — what to leave behind: outdated contacts, duplicate records, test data, unused custom fields' 12.

For Select fields whose source values do not match the destination, either: (1) extend the destination Select with the missing internal option names, (2) collapse adjacent values during transform, or (3) introduce a parallel Text field that holds the legacy value verbatim.

Formula and rollup fields do not import and are not yet supported as a Twenty field type 11 — rebuild the calculation in a workflow that fires on record-write, or compute it in the source layer and store the result in a static Number field.

Historical activities — notes, tasks, emails, calls

Twenty has Notes and Tasks as first-class standard objects 32. Historical free-form notes from a source CRM should be transformed into Notes records, each with a body, a createdAt timestamp, and a relation to the target record (Person, Company or Opportunity). Source activities of type Task become Twenty Tasks with dueAt, assigneeId and the same target-record relation.

Historical emails and calendar events are handled differently. Twenty's email and calendar sync (Google or Microsoft, with SMTP/CalDAV for others) is configured per-workspace-member under Settings → Accounts and runs forward-looking 102. There is no bulk historical-email importer in the way HubSpot ships one; if you need to preserve old email threads as activities, the working pattern is to transform each email into a Note record attached to the matching person, with the email body as the Note body.

Rich-text formatting in source notes is currently lossy — Twenty has an open request for a rich-text field type and the existing Long Text type renders as plain text 103. Convert HTML email bodies to plain text or Markdown before import.

Files and attachments

Attachments do not import via the CSV path. Twenty supports attachments on People, Companies, Notes and Tasks (the Attachments feature on Opportunity standard object is an open issue 121) — files are uploaded through the UI, then linked to the parent record.

For large attachment estates the working pattern is the same as Twenty itself recommends for most file storage: keep originals in S3, Google Drive or your storage provider, write a deep link into a custom Links field on the Twenty record, and only inline-upload the most recent or most-referenced subset. Self-hosted Twenty uses local volume storage by default (STORAGE_LOCAL_PATH=/data/twenty) with S3 configurable as an alternative 100.

Audit trail, ownership and original timestamps

Standard createdAt, updatedAt, createdBy and the internal id UUID are Twenty-managed system fields. The CSV path stamps createdAt to import time; if you need to preserve the original audit trail, the pattern is to create two custom Date & Time fields per object — *Legacy Created At* and *Legacy Updated At* — and populate them from the source export.

Owner assignment during import works only if the Workspace Member email exists at the moment of import; rows whose owner cannot be resolved import without an owner relation set, which silently breaks downstream owner-based workflows 83.

Audit-trail granularity has historically been a community concern — earlier releases lacked a built-in action history visible to admins 132. Newer releases ship a per-record activity log, but for compliance-grade audit trails on a self-host deployment, the durable answer is Postgres-level logging or a downstream warehouse stream rather than reliance on the application UI alone.

CRM-specific: lead scoring, sequences, email/calendar sync

Lead scoring as a first-class feature does not exist in Twenty — there is no scoring rule builder analogous to HubSpot Score or Salesforce Einstein Lead Scoring. The working pattern is a custom Number field (leadScore) updated by a Twenty workflow on record events.

Sequences and cadences are not native. Practitioners migrating from Outreach, Salesloft, HubSpot Sequences or Pipedrive Smart Docs need a different model — the workflow builder can chain wait-steps and task creations but lacks the cadence ergonomics of dedicated tools 30. For teams that depend on sequences, plan to pair Twenty with an external cadence tool, or wait on the workflow roadmap.

Email and calendar sync for ongoing forward-looking activity is configured per Workspace Member under Settings → Accounts with Google, Microsoft, or SMTP/CalDAV 102. Do not enable sync during the import window or you will get a flood of duplicate Notes as the connector backfills against the same people you are loading.

Section 06

The pitfalls that derail Twenty CRM migrations

Failure modes ranked by impact, each tied to the exact Twenty mechanism that breaks.

High impact

Custom fields not created before import

Twenty's CSV import creates records, not fields. Upload a file with a column for a non-existent field and the importer leaves you with no place to map it — the column shows up as unmapped and the data is dropped on confirm. The fix sits in the documentation as a Warning callout: 'Fields must exist before import. Create all custom fields in Settings → Data Model before importing.' Build the destination schema first, validate by downloading the template CSV, then load data 3878. 38

High impact

Owner / assignee users not invited before data lands

If your import references owners, account owners or assignees by email, those users must exist in Twenty before the import runs. Twenty's own Warning: 'Invite users BEFORE importing data. If your data includes user references, those users must exist in Twenty before import. Otherwise, those relations cannot be mapped.' Rows whose owner email cannot be resolved import with no owner set, which silently breaks every owner-filtered view and workflow downstream 83. 83

High impact

Domain format mismatch causes duplicate Companies

Twenty stores Company domains in URL form — https://acme.com. Import a CSV with acme.com or www.acme.com and Twenty does not match against existing records; you get duplicate Companies that have to be merged manually after the fact. The same canonical form must be used everywhere the domain appears (Company domainName, People companyDomain cross-reference column). Twenty's docs flag this as critical because the sync engine for email and calendar uses domain matching too 3. 3

High impact

Select field labels imported instead of internal option names

Twenty Select and Multi-Select fields have an internal option name distinct from the display label — the label is Closed Won, the option name is closedWon. The CSV importer expects the internal name in the column value. Loading display labels can either fail validation or silently miscategorise the row depending on field configuration. Enable Advanced Mode in Settings → Data Model to see the internal name for each option, and build your transform layer against those values 2226. 22

High impact

CSV row cap surprise — 2,000 then 10,000

Twenty's CSV import was historically capped at 2,000 rows per file, raised to 10,000 in later releases via issues #11372 and #11980 68. Teams sizing a one-shot migration off Salesforce or HubSpot row caps will hit this cliff. The fix is to split files (Twenty's own docs recommend splitting at 10,000 records) 3832. 8

Medium impact

Multi-select round-trip overwrites instead of merging

Practitioners hit a multi-select edge case on re-imports: upload a CSV with multiSelect1, then upload the same file with multiSelect2, and the records end up with only multiSelect2 — the previous value is overwritten rather than the two values being merged into a multi-value cell 14. Workaround: include all multi-select values in every row of every re-import. 14

Medium impact

Re-importing with previously defined id is partial

Twenty supports re-importing records with their previously assigned id UUIDs, which is essential if you are bouncing data through a sandbox or fixing a missed column after the fact. But issue #13195 documents that omitted columns in the second import are treated inconsistently — sometimes preserved, sometimes cleared. Build your re-import file as a *full* row replacement, not a partial-column update, and validate against a 10-row sample before the full re-run 33. 33

Medium impact

Views, workflows and permissions do not import

Twenty's documentation says it plainly: 'Views, workflows, and permissions must be recreated manually after migration. Plan time for this configuration work' 12. Teams that scope only the data migration discover post-cutover that every Kanban view, every saved filter, every workflow rule and every permission set is empty. Build a configuration checklist alongside the data mapping spreadsheet and budget one to three days for the rebuild on top of the data load. 12

Medium impact

Self-host scaling: Kanban lag and concurrent-user crashes

Practitioners self-hosting Twenty for 50-user teams have reported the system locking up under high concurrent card-creation load on the Kanban view, with hundreds of cards on screen producing visual bugs 87. The mitigation is right-sizing infrastructure (more than the 2 vCPU / 4 GB RAM minimum), keeping Redis and PostgreSQL on separate workers, and limiting Kanban views to a filtered subset rather than a full pipeline. Track GitHub for the active performance work before betting a large team on self-host. 87

Low impact

Compliance: GDPR / SOC2 attestation depends on deployment

Twenty self-host puts the data under your jurisdiction and your security controls — there is no Twenty SOC 2 audit covering your installation 38. Twenty Cloud handles infrastructure but the security attestation surface is narrower than HubSpot or Salesforce — verify the current SOC 2 / GDPR status with Twenty directly before signing off on a regulated-data migration. EU-residency-sensitive deployments can self-host in an EU region (Frankfurt, Amsterdam) with a $20–50/month VPS and full data sovereignty 38. 38

Section 07

Validation and cutover

What to verify after the import job, in what order — and how to fail safely when something is wrong.

1 Read-only Source goes write-frozen 2 Final delta Export incremental changes 3 Import Load into Twenty 4 Validate Reconcile + spot-check 5 Cut over Users on new system
Cutover sequencing — five gated phases between source read-only and full user access.

Validation is the bridge between the import finishing and users being allowed in. Practitioners recommend a three-stage validation for Twenty: a test load of 10 percent of records with stakeholder spot-checks, the full load with real-time monitoring of record counts and relation integrity, and a 30-day post-migration audit. The most reliable signal is having department reps verify their own records — they know what right looks like better than any reconciliation script.

Build a reconciliation queries spreadsheet that compares source and destination on each of these counts. Anything outside a 0.5 percent variance gets investigated before users get login access.

  • Total People imported vs source — minus deliberately excluded rows (role-based emails, opt-outs, stale 2+ year contacts).
  • Total Companies imported vs source — checking that domain-based dedup did not under- or over-merge.
  • Total Opportunities per pipeline stage vs source, plus sum of amount — a non-trivial dollar variance usually signals a stage-mapping error or a Currency precision drop (Twenty stores amounts in micros).
  • Total Notes and Tasks per parent record type imported vs source — and a date-bucketed comparison to confirm the legacy createdAt round-tripped into the custom Date field.
  • Relations per object type — count People→Company, Opportunity→Company and Opportunity→Person relations and compare against the source-derived expected counts.
  • Owner distribution — group by accountOwner and confirm no record landed unowned that should not have. Cross-check that every distinct owner in the source resolved to a Workspace Member.
  • Unique-identifier integrity — count distinct emails on People and distinct domainName values on Companies; duplicates indicate the dedup transform missed cases.

On top of reconciliation, run a manual spot-check protocol: pick 30 random records across objects via the table view filter, open each one, and verify every field against the source UI. Pick five high-value Opportunities and trace the full relation graph — point of contact, company, notes, tasks, attachments. If a non-trivial discrepancy shows up in three or more of the 30, halt the load, fix the root cause, and re-import the affected rows by id.

Rollback in Twenty is not a single button. Twenty 1.3.0 added a Merge Records action that lets you collapse duplicates after the fact, but there is no bulk-undo of an entire import.

The working rollback strategy is: export everything before the import starts (via the table view's export action, or SELECT * FROM against the workspace schema on self-host), stamp every imported row with an *Import Batch ID* custom Text field, and if catastrophe strikes, filter by that batch ID and bulk-delete from the table view, then re-import from the cleaned source.

On self-host, the strongest rollback option is a Postgres pg_dump immediately before cutover — restoring from that snapshot is the closest thing to an atomic undo Twenty offers. Twenty Cloud customers should request a workspace snapshot from Twenty support before the import if rollback is critical.

Cutover sequencing runs in seven steps. (1) Source goes read-only and the team is notified. (2) Final delta export captures everything that changed during the test-import window. (3) Delta is imported in the same Companies → People → Opportunities → Notes/Tasks → Custom Objects order 83.

(4) Reconciliation runs. (5) Views, workflows and permissions are rebuilt. (6) Users get login access and a 48-hour hyper-care window with the migration lead on call. (7) Source decommission is scheduled for 30 to 90 days out, never the same day.

Section 08

Migration partners and tools

Implementation partners, iPaaS vendors, and specialist migration shops — what each is good for and how to choose.

Twenty maintains an Implementation Partners programme listed inside the documentation; partners are referenced by Twenty's own docs as the people to call for very large datasets 38. Certified Twenty partners typically run fixed-scope migration packages — Salesforce-to-Twenty, HubSpot-to-Twenty, custom workflow rebuilds — alongside ongoing managed services that cover schema evolution and version upgrades after cutover.

Managed-deployment providers are a separate but adjacent ecosystem: several PaaS vendors ship one-click Twenty deployments starting around $14/month for small teams, and open-source self-host orchestrators offer documented Twenty configurations in their community discussions 100. These are infrastructure providers, not migration consultancies — they get the server running but the data move is still on you.

On the ETL and iPaaS side, Fivetran, Airbyte, Workato and Stitch can all be used to stage source data into a warehouse, transform it with SQL, then write into Twenty. As of mid-2026 the prebuilt Twenty connectors on these platforms are thin — most teams write a small Node.js or Python script rather than waiting for a managed connector.

Managed-migration cost ranges vary widely. A clean HubSpot- or Pipedrive-to-Twenty move of under 25,000 contacts with no historical activities and standard objects only often lands in the $500–$3,000 range from specialist migration vendors, with 48-hour turnaround. A Salesforce-to-Twenty project with custom objects, historical activities and workflow rebuild typically runs $5,000–$25,000+, with the upper end driven by record count, custom-object complexity, historical-data depth and the number of integrations that need re-pointed.

Self-service is genuinely viable for small teams: Twenty Cloud at $9/user/month plus a weekend of CSV preparation is enough for a 5,000-record consolidation. The cost case for outsourcing rises sharply with custom-object count, historical-activity depth, and Salesforce-Apex-style logic that needs to be rebuilt as Twenty workflows.

For teams that want to outsource the migration end-to-end, FlitStack specialises in Twenty CRM migrations and handles the field mapping, Select option-name conversion, historical-data preservation, custom-object schema setup, and validation work described in Sections 5 and 7 of this guide. Pricing is fixed-fee, based on record count and source platform, with separate line items for custom objects, historical activity depth, and self-host vs. Twenty Cloud delivery so the scope is transparent before signature.

This is one of several legitimate paths — the right choice for any given team depends on whether they want a certified Twenty partner, a self-service approach, an iPaaS-backed pipeline, or a specialist migration vendor. Explore FlitStack →

Section 09

Frequently asked questions

The questions every Twenty CRM migration team works through before they sign the scope.

References

Sources

  1. 1 Launch HN: Twenty.com (YC S23) — Open-source CRM
  2. 3 Migrating from Other CRMs — Twenty Documentation
  3. 6 Allow bigger imports than 2000 lines — twentyhq/twenty Issue
  4. 8 Data Migration — Twenty Documentation
  5. 11 Proposal: Computed Fields System — twentyhq/twenty Issue
  6. 12 Migrating from Other CRMs — Step-by-step audit + plan (Twenty Docs)
  7. 13 Supported File Formats — Twenty Documentation
  8. 14 Bulk updating records — Twenty CRM (multi-select round-trip)
  9. 18 Data Migration — CSV Import Basics (Twenty Docs)
  10. 22 Error Handling & Validation — Twenty Documentation
  11. 26 Create Custom Fields — Twenty Documentation
  12. 28 Zoho CRM is eating my time alive — r/smallbusiness
  13. 29 Twenty CRM — Sequence Follow-Ups (r/CRM)
  14. 30 Twenty CRM — Sequencing workaround discussion
  15. 32 Data Model — Twenty Documentation
  16. 33 Re-importing data with previously defined id fails — twentyhq/twenty Issue
  17. 36 Custom Objects (Metadata) — Twenty Documentation
  18. 38 Data Migration — Recommendations + Implementation Partners
  19. 41 Feature Request: Expand Standard Fields for People and Companies — twentyhq/twenty
  20. 42 Twenty Documentation
  21. 78 Migrating from Other CRMs — Create custom fields first warning
  22. 83 Migrating from Other CRMs — Invite users + import order warnings
  23. 87 Twenty self-hosted — concurrent-user concerns (r/selfhosted)
  24. 100 Twenty (CRM) on Coolify — environment + storage configuration
  25. 102 Calendar & Emails — Twenty Documentation
  26. 103 Add rich text field type — twentyhq/twenty Issue
  27. 121 Enable Attachments feature on Opportunity standard object — twentyhq/twenty
  28. 132 Twenty self-hosted — audit-trail concerns (r/selfhosted)
  29. 151 Migrating from Other CRMs — Large Migrations (50,000+) guide
  30. 153 Support for Multiple Pipelines on One Object (Record Types) — twentyhq/twenty

Need help running this migration?

FlitStack AI runs Twenty CRM migrations end-to-end.

Fixed-fee pricing, a hands-on migration engineer, full field mapping and validation. The work described in this guide — done for you.