CRM migration

Migrate from Civicrm to Twenty CRM

Field-level mapping, validation, and rollback between Civicrm and Twenty CRM. We move data and schema; workflows are rebuilt natively in Twenty CRM.

Civicrm logo

Civicrm

Source

Twenty CRM

Destination

Twenty CRM logo

Compatibility

50%

6 of 12

objects map 1:1 between Civicrm and Twenty CRM.

Complexity

BStandard

Timeline

3-5 weeks

Rollback included Accuracy guarantee Field-level validation

Overview

What this migration involves

Moving from CiviCRM to Twenty CRM is a model-aware migration, not a straightforward record copy. CiviCRM uses an Activity-based engagement model where calls, emails, meetings, and tasks are all Activity subtypes with type IDs, while Twenty separates these into native Task, Note, and Event objects. We resolve that translation during scoping and preserve the original CiviCRM Activity type as a tag on each imported record. CiviCRM's relationship network (household membership, spousal, employee-employer) maps to Twenty's People-to-Company relationship system, with Organizations handled as Company records. CiviCase statuses are defined per-case-type in XML or PHP entityType rather than as a global list — we enumerate every active case_type during discovery and map each status set individually. Custom fields (single-record and multi-record) land as Twenty custom fields with their original labels preserved. ECK (Entity Construction Kit) entities, CiviMail mailings, CiviRules automated processes, and any Drupal/WordPress/Joomla CMS user accounts do not migrate; we deliver a written inventory of these for the customer's admin to assess.

Field-level fidelity

Every standard and custom field arrives verified.

Schema-aware mapping

AI proposes the map; you confirm before any record moves.

Relationships preserved

Parent–child, lookups, and ownership stay linked.

Full activity history

Calls, emails, meetings — with original timestamps.

Attachments & notes

Documents, uploads, and inline notes move with the record.

Why teams make this switch

Two sides of the same decision

Leaving

Civicrm logo

Civicrm

What's pushing teams away

  • The UI is dated compared to modern SaaS CRMs — reviewers describe the interface as old-fashioned and the search mechanics as database-query style rather than intuitive keyword search.
  • Steep technical learning curve — multiple Capterra and G2 reviews note that configuring CiviCRM well requires dedicated developer or consultant resources that smaller non-profits cannot afford.
  • No native bulk data export — data portability relies on the API or manual exports; there is no one-click comprehensive dump, making migration planning time-intensive.
  • Hosting complexity is a hidden cost — because the software is self-hosted, organizations must budget for server infrastructure, security patching, and PHP/MySQL maintenance.
  • Performance bottlenecks tied to hosting — slow queries, PHP execution limits, and MySQL configuration tuning fall on the organization's technical team rather than a vendor.

Choosing

Twenty CRM logo

Twenty CRM

What's pulling them in

  • Top open-source CRM on GitHub with 40.6K stars, giving teams full source code access and infrastructure ownership without per-feature licensing surprises.
  • Free self-hosting under AGPL-3.0 means unlimited users and custom objects for the cost of cloud infrastructure alone, typically $20–100/month.
  • Pricing page explicitly mocks competitors for charging add-on fees for API access, webhooks, and workflows — transparency that resonates with RevOps teams burned by Salesforce.
  • Unlimited custom objects and fields with no price impact, letting teams shape the data model to their business rather than forcing business into rigid schemas.
  • Modern TypeScript/React/PostgreSQL stack means developer-led teams can extend, self-host, or integrate without fighting legacy architecture.

Object mapping

How Civicrm objects map to Twenty CRM

Each row shows how a Civicrm object lands in Twenty CRM, including any object-level transformations, lookup resolution, or schema-design dependencies.

Typical mapping — final map is confirmed during the sample migration step.

Civicrm

Contact (Individual, Household, Organization)

maps to

Twenty CRM

People or Company

1:many
Fully supported

CiviCRM Individual contacts map to Twenty People. Organization contacts map to Twenty Company. Household contacts — a CiviCRM-specific subtype representing multi-person family units — present a mapping challenge because Twenty has no Household equivalent. We map Household contacts to Twenty Company records (using the Household name as displayName) and store the member relationship in a custom relationship field on each People record. The contact network relationship chain (spousal, employee-employer, household membership) is preserved via Twenty's relationship system, with the original CiviCRM relationship type ID stored as a tag for audit.

Civicrm

Activity

maps to

Twenty CRM

Task, Note, or Event

1:many
Fully supported

CiviCRM Activity is a unified engagement record with activity_type_id distinguishing call, email, meeting, and other types. We split Activities at migration time: type_id 1 (Meeting) maps to Twenty Event, type_id 2 (Email) maps to Note with an is_email flag, type_id 3 (Call) maps to Task with TaskSubtype=Call, and all other types map to Task. The original CiviCRM activity_type_id is preserved in a custom tag on the target record. Activity assignments (assignee_id) map to Twenty workspace members by email match.

Civicrm

Group and GroupContact

maps to

Twenty CRM

People segment or tag

lossy
Fully supported

CiviCRM Groups with static membership (GroupContact records) map to Twenty tags on People records. We preserve the group hierarchy where it exists. Dynamic (smart) groups that use CiviCRM search-based filtering cannot be fully reproduced because Twenty does not have a smart-group equivalent — we document each dynamic group's criteria as a written filter definition for the customer to recreate manually in Twenty's filter system.

Civicrm

Contribution

maps to

Twenty CRM

Custom Object (financial_payment) or Opportunity

lossy
Fully supported

CiviCRM Contributions include financial_type, total_amount, currency, receive_date, payment_instrument, and source. We create a financial_payment custom object in Twenty (via Settings → Data Model) with fields for amount, currency, payment date, payment method, and contribution source. Organizations that prefer Opportunity tracking for donations map Contributions to Opportunity records using a donation record type. Price Sets on Contributions introduce variable line-item complexity that must be flattened — we flatten to a single total_amount unless the customer requests line-item preservation.

Civicrm

Membership

maps to

Twenty CRM

Custom Object (membership)

lossy
Fully supported

CiviCRM Membership records include type, status, start_date, end_date, and source. Membership Price Sets allow complex tier structures. We create a membership custom object in Twenty with fields for membership_type, status, start_date, end_date, and source, linked to the Company record representing the member organization or the People record for individual members. Membership status transitions (e.g., New → Current → Expired) are preserved as tags rather than native status workflows.

Civicrm

Event

maps to

Twenty CRM

Event

1:1
Fully supported

CiviCRM Events map to Twenty Event records. We map event title, start_date, end_date, location, description, and event_type. Price sets and participant fees flatten to a single registration_fee field. Participant roles (Attendee, Speaker, Volunteer) migrate as tags on the Event. Online registration profiles are not migrated as forms — we document the registration configuration for the customer's admin to recreate in Twenty's form or external registration tool.

Civicrm

Case (CiviCase)

maps to

Twenty CRM

Custom Object (case) or Task chain

lossy
Fully supported

CiviCase stores case_id, case_type, status, start_date, and a set of related activities. Case statuses are defined per case_type in XML or PHP entityType — they are not a global status list. We enumerate every active case_type during discovery, extract its status option values, and map each set individually to a status picklist on the Twenty case custom object. The activity chain (case timeline) migrates as a sequence of Task records with a custom case_id reference. Cases that reference specific case_type XML files require us to parse those files during scoping.

Civicrm

Custom Fields (single-record Custom_*)

maps to

Twenty CRM

Custom object fields

1:1
Fully supported

Single-record custom groups appear as fields on the parent entity via the custom.* selector in CiviCRM APIv4. We map each custom field to a typed Twenty custom field (text, number, date, picklist, multi-select picklist) on the corresponding object. Field labels and help text are preserved. Picklist options migrate as picklist values in Twenty's field settings.

Civicrm

Custom Fields (multi-record Custom_*)

maps to

Twenty CRM

Custom object with line items

1:1
Fully supported

Multi-record custom groups appear as separate entities prefixed Custom_ in CiviCRM. We create a custom object in Twenty for each multi-record group and link it to the parent contact record via a lookup relationship. For sites with more than approximately 20 custom groups, we query individual records entity-by-entity rather than using APIv4's custom.* wildcard selector to avoid exceeding MySQL's maximum join count (61 joins). The multi-record table structure is flattened into a standard custom object row format.

Civicrm

Relationship

maps to

Twenty CRM

Relationship

1:1
Fully supported

CiviCRM Relationships connect contacts (household member, employee-employer, spousal, etc.) with a relationship_type_id and bidirectional flag. We map each Relationship to Twenty's relationship system, resolving both contact references by their CiviCRM contact_id. The original relationship_type_id is preserved as a tag for audit. Bidirectional relationships are mapped as a single relationship in Twenty.

Civicrm

Tag

maps to

Twenty CRM

Tag

1:1
Fully supported

CiviCRM Tags are flat labels attached to any entity via the EntityTag join table. We map tag names to Twenty tags, preserving the entity_id link on each migrated record. Multi-entity tagging (a tag applied to both a Contact and an Event) is handled with separate tag associations per record.

Civicrm

Grant (CiviCRM extension)

maps to

Twenty CRM

Custom Object (grant)

1:1
Fully supported

Grants is an optional CiviCRM extension module. Where present, we create a grant custom object in Twenty with fields for grant_type, amount_requested, amount_granted, status, and deadline. Grant data often has tight coupling to the CMS user that submitted it — we map the CiviCRM contact associated with the grant rather than the CMS user account.

Gotchas + challenges

What specifically takes care here

Platform-specific issues from each side, plus the pair-specific challenges that don't show up on either platform's page on its own.

Civicrm logo

Civicrm gotchas

High

Server-to-server migration requires CMS settings file portability

Medium

Multi-record custom groups can hit MySQL's 61-join limit

Medium

No native bulk export — data portability is API- or database-dependent

Medium

CiviCase statuses are per-case-type — not a global status list

Low

Hosted Spark tier has no documented API rate limit — performance varies by plan

Twenty CRM logo

Twenty CRM gotchas

High

Import order is enforced and critical

High

Export limited to 20,000 records and visible columns only

Medium

Soft-deleted records count toward uniqueness and trigger restores

Medium

API rate limits cap at 200 req/min on Organization tier

Low

No native email sequences — follow-up cadences require external tools

Pair-specific challenges

  • CiviCase statuses are per-case-type, not global

    CiviCase defines status values within each case_type definition via XML or PHP entityType. Status IDs are scoped to the case_type and are not global integers. Mixing status values across case_types during import produces silent mis-assignments where a status label from one case_type appears under the wrong case in Twenty. We enumerate every active case_type during scoping, extract each status option set individually, and map them to a status picklist on the Twenty case custom object. This enumeration step adds one to two days to discovery.

  • ECK entities have no standard Twenty mapping

    The Entity Construction Kit (ECK) extension in CiviCRM allows arbitrary custom entity types with user-defined properties and custom field attachments. These represent organizational schemas that exist outside the standard CiviCRM data model. Twenty's custom object system via Settings → Data Model provides a general-purpose target, but each ECK entity requires a custom schema design pass. We treat ECK entities as custom objects and flag them separately during scoping for explicit customer confirmation before migration begins.

  • Multi-record custom groups can exceed MySQL join limits

    CiviCRM APIv4's custom.* wildcard selector adds one MySQL join per custom group. Sites with a large number of custom groups (approximately 20 or more) can exceed MySQL's maximum join count, causing a fatal error during export. We query the custom group count during scoping and fall back to individual entity-by-entity exports for sites exceeding the safe join limit, which increases migration time for heavily customized instances.

  • CiviMail mailings and CiviRules do not migrate

    CiviMail mailing records (subject, body HTML, recipient groups, delivery statistics) are tightly coupled to the CiviCRM mailing infrastructure — SMTP configuration, SPF/DKIM settings, and the mailing queue. They cannot be reproduced in Twenty without rebuilding the entire email sending infrastructure. Similarly, CiviRules automated processes (event-triggered workflows) are extension-scoped and have no direct equivalent in Twenty. We deliver a written inventory of each mailing and CiviRule for the customer's admin to assess for rebuild.

  • CMS user accounts do not cross the migration boundary

    CiviCRM integrates with Drupal, WordPress, Joomla, or Backdrop CMS, and user authentication lives in the CMS layer. The CiviCRM contact record is separate from the CMS user account. We migrate only the CiviCRM contact data. CMS user accounts, role-based permissions in the CMS, and any CMS-specific content (webforms, event pages, donation pages) are outside migration scope. We document these dependencies in the scope letter for the customer's technical team.

Migration approach

Six steps for a successful Civicrm to Twenty CRM data migration

  1. Discovery and export path assessment

    We audit the source CiviCRM instance across CMS integration (Drupal, WordPress, Joomla, Backdrop), PHP/MySQL version, CiviCRM version, CiviSpark tier (if hosted), API credentials, direct database access, and extension set. We identify ECK entity schemas, count custom groups, enumerate active case_types and their status option values, and assess the activity volume by type. We also determine the export path: REST API-first for Contacts, Activities, Groups, and Events with direct MySQL reads for large-volume custom tables and multi-record Custom_ groups where API pagination would be prohibitively slow.

  2. Data model design and custom object creation

    We design the destination schema in Twenty. This includes creating custom objects for Contributions (financial_payment), Memberships (membership), Cases (case), Grants (grant), and any ECK entities. We configure custom fields on People and Company for migrated single-record custom fields. We establish the CiviCase status picklist with values drawn from the per-case-type enumeration. Schema is built via Twenty's Settings → Data Model UI, with field types matched to CiviCRM data types (text, number, date, picklist, multi-select). Workspace members are invited before any record import so that assignee lookups can resolve during migration.

  3. Test migration in Twenty sandbox

    We run a representative subset migration (1,000-2,000 contacts, a sample of activity types, one case_type with its full status set) into a test Twenty workspace. The customer's team reconciles record counts, spot-checks 20-30 records against the CiviCRM source, validates the Activity-to-Task/Note/Event split, verifies case status mapping, and confirms relationship chain integrity. Mapping corrections are made here before the production migration begins.

  4. Contact and Organization migration

    We migrate in strict dependency order: Organization contacts (to Company) first, then Individual contacts (to People with Organizations resolved via CompanyId lookup), then Household contacts (to Company with member relationship tags). Each phase emits a row-count reconciliation report. Any contact without an email or phone is flagged for customer review. Duplicate detection uses email as the dedupe key with a secondary check on displayName for organizations.

  5. Activity history migration

    We split Activities by type during the transform phase. Meetings land as Twenty Event records with start/end times. Emails land as Note records with a custom email flag. Calls land as Task records with TaskSubtype preserved. All other Activity types land as Task records. The original CiviCRM activity_type_id is stored as a tag. Activities are imported after all People and Company records exist so that the assignee and target record lookups resolve without orphaned references.

  6. Financials, memberships, cases, and custom data

    Contributions migrate to the financial_payment custom object linked to the contributing contact. Memberships migrate to the membership custom object linked to the member contact. Cases migrate to the case custom object with the per-case-type status mapping applied and the activity chain reconstructed as Task records with a case_id reference. Multi-record custom groups migrate to their corresponding custom objects with parent lookups resolved to the CiviCRM contact_id preserved as a legacy_id field. ECK entities migrate as their own custom objects with explicit customer sign-off on each schema before import.

  7. Cutover, validation, and scope handoff

    We freeze writes in CiviCRM during cutover, run a final delta migration of records modified during the migration window, then enable Twenty as the system of record. We deliver the ECK entity inventory, CiviMail and CiviRule inventory, dynamic group criteria definitions, and CiviRules rebuild recommendations. We do not rebuild CiviRules as Twenty workflows inside the migration scope; that work is documented for the customer's admin. We support a one-week post-cutover window for reconciliation issues.

Platform deep dives

Context on both ends of the pair

Civicrm logo

Civicrm

Source

Strengths

  • Free open-source download with no per-seat licensing — only hosting costs apply.
  • Nonprofit-native objects: Contributions, Memberships, Grants, Events, and Cases without sales-CRM workarounds.
  • Unlimited record count — G2 reviewers report instances with 1M+ contacts running without per-record billing.
  • Custom data model via custom fields, multi-record sets, and ECK entities for arbitrary organizational schemas.
  • Active open-source community maintaining extensions for Drupal, WordPress, Joomla, and Backdrop CMS integrations.

Weaknesses

  • Dated web interface — search is database-query style rather than modern keyword search; UI consistency varies by CMS integration.
  • No native bulk export or one-click migration tooling — data portability relies on API, direct MySQL access, or manual CSV exports.
  • Performance and API rate limits are hosting-dependent rather than platform-enforced; self-hosting requires dedicated technical resources.
  • Steep configuration learning curve — multiple G2 and Capterra reviewers cite the need for developer or consultant time to configure effectively.
  • No built-in workflow automation without third-party extensions like CiviRules, adding migration complexity for automated processes.
Twenty CRM logo

Twenty CRM

Destination

Strengths

  • AGPL-3.0 open-source license with full source code on GitHub — no vendor lock-in, no sunset risk.
  • Unlimited users and unlimited custom objects on self-hosted, with no feature gating based on headcount.
  • REST and GraphQL APIs available on all paid tiers, not locked behind an enterprise add-on fee.
  • MCP server and webhooks shipped as standard features, not premium upgrades.
  • Modern PostgreSQL-backed data model that developer teams can query, extend, and self-host.

Weaknesses

  • Recent v1.0 release means limited production hardening compared to CRMs with multi-year operational track records.
  • No native email sequencing or sales engagement tools — follow-up cadences require a separate platform.
  • No native two-way email sync or inbox integration, requiring third-party connectors for full activity logging.
  • Self-hosting 'free' pricing hides real infrastructure and DevOps costs that stack up over time.
  • Workflow automation is functional but lacks the complexity needed for sophisticated multi-step sales motions.

Complexity grading

How hard is this migration?

Standard CRM migration. 1 of 8 objects need a mapping; the rest are 1:1.

B

Overall complexity

Standard migration

Derived from compatibility, mapping clarity, API constraints, and data volume across Civicrm and Twenty CRM.

  • Object compatibility

    B

    1 of 8 objects need a mapping; the rest are 1:1.

  • Field mapping clarity

    C

    Field mapping is derived from defaults — final spec confirmed during the sample migration.

  • Timeline complexity

    B

    8-object category — typical timelines run 2–7 days end-to-end.

  • API constraints

    B

    Civicrm: Not publicly documented — Spark tier has no published limit; self-hosted performance is infrastructure-dependent.

  • Data volume sensitivity

    B

    Civicrm doesn't expose a bulk API — REST + parallelization used for high-volume runs.

Estimator

Estimate your Civicrm to Twenty CRM migration cost

Rule-based pricing — no per-record fees, no manual quotes. Migrations over 2M records are scoped individually.

Step 1

What are you migrating?

Pick a category, then your source and destination platforms.

Category

FAQ

Frequently asked questions about Civicrm to Twenty CRM data migrations

Answers to the questions buyers ask most during Civicrm to Twenty CRM migration scoping. Not seeing yours? Book a call.

Can't find your answer?

Walk through your Civicrm to Twenty CRM migration with a real engineer — 30 minutes, free, written quote within 24 hours.

Book a free 30 minute consultation

Most migrations land between three and five weeks for instances under 10,000 contacts, no ECK entities, and fewer than five active case_types. Migrations with ECK custom schemas, large activity histories (over 200,000 Activity records), multiple case_types requiring individual status enumeration, or multi-record custom groups exceeding the MySQL join limit move to eight to fourteen weeks. The per-case-type status enumeration step alone adds one to two days to discovery.

Adjacent paths

Related migrations to explore

Ready when you are

Move from Civicrm.
Land in Twenty CRM, intact.

Tell us record counts and timeline. We'll come back with a written quote inside 1 business day — no commitment, no sales pitch.

Accuracy guarantee Rollback included Quote in 1 business day