Migrate from spreadsheets to EspoCRM: what the move involves
If your accounts, contacts and opportunities live in scattered Excel or Google Sheets files, the move to EspoCRM means turning those files into one shared record that the whole team trusts. The work is mostly data preparation, field mapping and a controlled import, not software installation. Effort is driven by two things: how clean the spreadsheets are today, and how many entities you need to load, since accounts, contacts and opportunities each have their own columns, links and duplicate rules. The EspoCRM Import tool reads CSV files only, so every spreadsheet has to be exported and saved as UTF-8 CSV before anything else happens. It is found at Administration > Import and is run by administrators. The EspoCRM import documentation also warns that any user granted Import access through Roles should be treated as privileged, because that person can create or overwrite large volumes of records. Decide early who will run imports and who may be granted the permission, and record that decision as part of the plan.
DeployOpen works within this documented import path rather than around it. In practice that means agreeing the scope in writing before work starts: which spreadsheets and tabs are in scope, which EspoCRM entities they map to, who owns the business rules for duplicates and blank values, and what must be checked before go-live. Ask any partner, including us, to show how they will profile the source data, which exceptions they expect, and how each import batch will be reviewed and reverted if needed. Clean-up that is done in the spreadsheet before export is usually cheaper than correcting records after they are in the CRM.
Which spreadsheet columns map cleanly to EspoCRM and which need design
This table compares common spreadsheet structures against EspoCRM accounts, contacts, opportunities, teams and user assignments. Read each row as a decision: the column either maps directly, needs a custom field or fixed option list, or should stay out of the CRM. The main takeaway is that most of the effort sits in status values, owner names and multi-contact layouts, not in the basic name and address fields.
| Sheet structure | EspoCRM target | What to decide before import | Where it usually goes wrong |
|---|---|---|---|
| One row per customer | Account | Confirm the account name is unique enough to act as the duplicate match field | Subsidiaries and branches share a name and get merged on import |
| Several contacts stacked under one company | Account plus multiple Contact records | Decide whether each contact row links to its account by a company name or an account ID you add | Name-only matching creates duplicate accounts with slightly different spellings |
| Opportunity tab or separate sheet | Opportunity linked to Account | Map the account key column so each opportunity points to exactly one account | Opportunities import without a parent account and appear orphaned in pipeline views |
| Dropdown status values such as Hot, Warm, Won, Pending | Enum fields on Opportunity or Lead | List every distinct value and map it to an existing option or add options in the Entity Manager first | Values that do not match an option are rejected or stored as text that breaks reports |
| Owner or rep names typed as text | Assigned user and team | Match each name to an active EspoCRM user and decide which team owns the record | Former staff names have no user, so records are left unassigned or assigned to the importer |
| Notes or comments column | Stream posts, or a custom text field | Decide whether notes become history entries or a single long text field, and keep their date | Long free-text notes truncate or lose their original dates |
| Industry, region or segment columns | Custom field, or an existing field if one fits | Add a custom field in the Entity Manager when no standard field fits, and fix its option list | Free-text segments create near-duplicate values that split filters and reports |
| Renewal date, contract value, probability | Opportunity date and amount fields, plus custom fields if needed | Confirm the currency and decimal format, and whether probability is a number or a stage | Locale formats such as day-first dates import as wrong months |
| Personal data columns not needed for selling or service (for example, national ID numbers, bank details, health notes) | Not imported | Remove them from the file and document why, which supports data minimization reviews | Sensitive columns get copied into a broadly visible CRM and then need a cleanup project |
Documented import paths and what each one is for
EspoCRM gives you one documented way to load spreadsheet data through the web interface, plus an API for later automation. The cards below cover what the CSV import tool does, who can use it, and where the risks sit, so you can decide how your migration runs before any file is touched.
CSV import at Administration > Import
The import tool reads CSV files and is opened from Administration > Import. It is the path most spreadsheet migrations use, because each file maps directly to one entity such as accounts, contacts or opportunities. Load one entity type at a time, and confirm the file encoding and column headers before the first real run. Test with a copy of a few hundred rows in a non-production instance first.
Create, update and update-only modes
The import tool offers three modes: Create Only, Create and Update, and Update Only. Create Only is the safest choice for a first load into an empty system. Create and Update fits a second pass that refreshes existing records, while Update Only should be used when you want to change records that already exist without adding new ones. Pick the mode per file and record the choice in your migration log.
Field mapping and duplicate matching
Field mapping connects each spreadsheet column to an EspoCRM field, and duplicate matching decides which existing records a row updates. Choose match fields that are stable and unique in your data, such as an external customer ID or a normalized email address, rather than a name that people spell differently. Review a sample of matches before running the full file, because a weak match key silently merges unrelated customers.
Idle execution through cron
Large files can run in idle mode, where the work is handled by the scheduled job runner rather than the browser session. This requires cron or a scheduled task to be configured on the server, so confirm it is running before you start a large import. Check the job status and error output after completion, and schedule imports outside working hours so the runner does not compete with users.
Access through Roles and privileged use
Import access can be granted to other users through Roles, not only to administrators. The documentation warns that anyone with Import access should be treated as privileged, because a single file can create, overwrite or bulk-change many records. Limit the permission to a small migration team, remove it after cutover, and review the role assignments in your security checklist.
REST API for later automation
The REST API is a route for scripted loads and recurring syncs once the initial migration is complete. Use dedicated API users with narrow role permissions rather than personal accounts. Before building anything on the API, confirm its request limits and endpoint behavior with the EspoCRM API documentation, because a script that works in a test instance can behave differently under production volume.
How to prepare UTF-8 CSV files so the import does not fail halfway
Most of the effort in a spreadsheet migration sits in preparing the files, not in running the import. EspoCRM's Import tool reads CSV files, so every file needs one encoding (UTF-8), one delimiter used consistently, and exactly one header row. Mixed encodings usually show up as garbled accented names or broken currency symbols after import, and a stray merged header row can shift every column by one. Check each file in a plain text editor before upload, and confirm that the delimiter your export tool produces matches what you choose in the import wizard. Spreadsheet exports often add a byte order mark or convert values such as long account numbers or ZIP codes into scientific notation, so inspect a sample of rows after export rather than trusting the first screen.
Clean the data before it reaches EspoCRM. Trim leading and trailing whitespace, since " Acme Ltd " and "Acme Ltd" will not match on duplicate detection. Normalize phone numbers to one format, ideally international notation, and store country values in one agreed form, such as ISO country codes, so that field mapping and any later dropdowns behave predictably. Resolve duplicate customer rows inside the spreadsheet before import, because the Import tool's duplicate matching on chosen fields is only as good as the keys you give it. Decide which row wins when two rows describe the same customer, and record that decision. Add a source ID column to every file that holds the original spreadsheet row or legacy key. This column lets you trace any EspoCRM record back to its source, reconcile counts after each run, and rerun a corrected file in Update Only mode without creating new records. Confirm the exact field names and any limits for your EspoCRM version in the import documentation, and test with a small sample file before loading the full dataset.
Migration sequence from inventory to decommissioning the spreadsheets
This sequence moves customer data out of spreadsheets and into EspoCRM in a controlled order, with a tested revert path, a parallel run and an archived copy of the sheets that remain available as reference.
Inventory every sheet and its owner
List each spreadsheet, shared drive folder and local file that holds customer, contact, account or pipeline data, and record who maintains it, who reads it and which reports or mail merges depend on it. Note which columns are actually used and where the same customer appears in several files. The output is a signed-off inventory that the sales, service and finance owners have reviewed, with each sheet marked as migrate, archive or discard. Confirm with each owner that nothing important lives only in a personal copy.
Build the cleaning and mapping workbook
Create a workbook that maps every source column to an EspoCRM field on accounts, contacts or opportunities, and lists the rules for cleaning values: trimming spaces, standardizing country and phone formats, merging duplicate accounts and resolving conflicting owners. Save each CSV as UTF-8 and check that dates and currency values follow the format your import will expect. The workbook is done when every column has a target or an explicit reason to drop it, and the business owners have approved the duplicate rules.
Run a pilot import into a non-production instance
Load a representative sample of accounts, then contacts linked to those accounts, then opportunities linked to accounts and contacts, into a non-production EspoCRM instance. Use the Import tool with field mapping and the duplicate matching fields you chose in the workbook. Review each batch for unmatched links, wrong field types and unexpected duplicates, then correct the workbook and repeat until the sample loads as expected. The output is a pilot log that records the rows loaded, rows rejected and the fix applied to each error.
Test a revert of the pilot import
Before any production load, use EspoCRM's revert function on the pilot import and confirm that the imported records are removed and that records created by users in the meantime are not affected. Check the results in the user interface and in the record counts for each entity. Also confirm that users with Import access are limited to the people you intend to trust, because the documentation treats them as privileged. The revert test is complete when the pilot data is gone, the counts match the pre-import state and the outcome is written into the cutover runbook.
Import production data in dependency order
Run the production import in three passes: accounts first, then contacts linked to their accounts, then opportunities linked to accounts and contacts. Each pass should use the duplicate rules and mapping that the pilot approved, and each file should be checked for links to records created in an earlier pass. Keep the import log for every run so that any pass can be reverted independently. The step is finished when record counts match the cleaned source files and a sample of records has been checked against the original sheets.
Run the parallel period with sheets read-only
Have the teams work in EspoCRM for all new activity while the original spreadsheets stay open for reference only, with edit rights removed or the files marked read-only. Track questions, missing fields and data that users discover is wrong, and fix them in EspoCRM rather than in the sheets. The period ends when the team reports no gaps that block daily work and the open issues list is closed or accepted by the business owners.
Cut over and archive the spreadsheets
Declare the cutover date, make a final import of any changes made in the sheets during the parallel period if they were not already captured, and then make the sheets read-only for everyone. Export a complete archived copy of each file to a controlled location with retention rules agreed by the data owner, and record where the copy is kept. Confirm that reports, mail merges and integrations that depended on the sheets have been replaced or retired.
Decommission the sheets and keep the audit trail
Remove the working spreadsheets from shared drives and personal folders according to the archive plan, and revoke any sharing links. Keep the cutover runbook, pilot log, production import logs and the archive index together so that any later question about where a record came from can be answered. The sequence is complete when the sheets are no longer used for customer data, the archive is verified as readable and the owners have signed off the decommissioning record.
Handling relations and duplicates during import
In a spreadsheet, a contact sits on the same row as its company, or carries a company name in a column. EspoCRM stores these as relationships between records, so the import has to resolve each text value in a child row to an existing account before the link can be made. The import order matters here: accounts must exist before contacts and opportunities refer to them. Confirm in the Import documentation and on your version exactly which field the importer uses to find the parent record, because the lookup behavior is the part most likely to differ from what you expect.
- Pick one stable key: Use an account identifier that does not change, such as an ID from your old system or a unique account code, rather than a company name that people spell several ways.
- Handle missing link values: Rows with an empty parent key will either import unlinked or fail, depending on the mapping you choose. Filter these rows into a separate file and decide whether each one needs a new account or a correction.
- Watch for ambiguous matches: If two accounts share a name, a name-based lookup cannot know which one is meant. Resolve these in the source file before import.
- Check opportunity ownership: Opportunities usually need an account link and an assigned user. Map the user column to valid EspoCRM usernames, not display names.
- Spot-check relations after each run: Open a sample account and confirm its contacts and opportunities appear in the expected panels.
Before the full run, import a small batch of accounts and their contacts into a test instance and confirm every link resolves.
Duplicate handling depends on which fields the importer compares to decide whether a row matches an existing record. EspoCRM lets you choose the matching fields during import, so the decision belongs in the mapping plan, not in the cleanup afterward. A weak match field, such as a common first name or a generic email alias, produces false matches. A strict field, such as a case-insensitive email address, misses variations. Choose fields that are unique in practice for your customers, and confirm how the importer treats case and whitespace on your version.
- Prefer identifiers: External IDs, tax numbers or account codes usually outperform names as match fields.
- Normalize before import: Trim spaces, standardize case for emails and remove duplicate header rows so the comparison works on clean values.
- Test on a sample: Run the matching logic on a copy of about one hundred representative rows and review what it matched before using it on the full file.
- Document the chosen fields: Record which fields were used for each entity, so later imports and audits can reproduce the decision.
- Keep contact matching separate: Contacts often need email as the key, while accounts need a company identifier. Treat them as separate rules.
Check that every match field you select is populated in the source file for most rows, because blank values make matching unreliable.
The import modes decide what happens when a row matches an existing record. Create Only adds new records and skips rows that match, which suits a first migration into an empty or mostly empty instance. Create and Update adds new records and also overwrites matched records with values from the file, which suits a second pass that corrects data. Update Only changes existing records and ignores new ones. The mode you choose changes what can be overwritten, so set it deliberately for each entity and each run.
- Use Create Only for the first load: It leaves records that already exist in EspoCRM untouched, so a rerun cannot quietly replace data entered by users.
- Use Create and Update with care: Overwrites apply to every mapped field, including blank values if the file contains them. Map only the fields you intend to change.
- Run a second pass deliberately: After reviewing duplicate candidates, use Update Only or Create and Update on a limited file of corrections.
- Consider assigned users: Overwrites can reassign ownership if the owner column is mapped. Exclude ownership fields from updates unless you mean to change them.
- Plan for large files: The documentation notes that cron-driven idle execution handles large files, so confirm the scheduled job runs before starting.
Confirm on your EspoCRM version exactly which fields an update overwrites, and test the mode on a non-production instance first.
Duplicates rarely come from the importer alone. They usually come from several spreadsheets that describe the same customers in different ways, or from users who created records in EspoCRM while the migration was underway. A review step before a second run catches these cases while they are still easy to fix. Pull the candidate list from your matching fields, group rows by match key, and decide for each group whether to merge in the source file, keep both, or exclude the row. Then rerun only the corrected subset with the mode you planned.
- Group by match key: Sort the source file by the chosen fields so repeated keys sit together and are easy to scan.
- Compare against live data: Search EspoCRM for records created since the first import, because users may have added customers during the migration window.
- Keep an exception log: Record every row you excluded or merged, with a reason, so the decision can be explained later.
- Use the revert option for bad runs: If a rerun goes wrong, the import tool supports reverting imported records, so confirm that the revert path works in a test before you rely on it.
- Restrict import access: Users with Import access should be treated as privileged, so limit it to the people running the migration.
Before the production rerun, confirm the revert procedure, the exception log and the list of users allowed to run imports.
What drives the cost and duration of a spreadsheet migration
This table lists the factors that change the effort of moving spreadsheet data into EspoCRM, why each one matters and what to ask for in a written quote. Read it before comparing quotes, because a low number often reflects a smaller scope rather than a cheaper method.
| Driver | Why it changes effort | What to ask for in a quote |
|---|---|---|
| Number of sheets and entities | Each sheet that maps to a separate entity adds a mapping, an import run and a validation pass. Merging sheets into fewer entities removes work but may change how records relate. | A sheet-by-sheet inventory showing which entity each sheet maps to and the import order |
| Row counts and data quality | Large files need cron-driven idle execution, and inconsistent names, phone formats or duplicate accounts add cleaning rounds before any import runs. | A stated assumption on row counts per sheet and a list of cleaning steps the quote includes or excludes |
| Custom fields in the Entity Manager | Columns with no matching EspoCRM field require new fields, types and options to be created before import, which adds configuration and testing. | A field map listing each spreadsheet column, its target field and whether the field is new |
| Layouts, teams and access to set up first | Layouts, teams and default assignment rules must exist before records arrive, or imported data appears in the wrong views for the wrong people. | Confirmation of which layouts, teams and assignment rules are built and tested before the first import |
| User and role design | Import access is a privileged permission in EspoCRM, so role design, user creation and the number of people allowed to import affect both setup time and control reviews. | Role definitions, the named users who will run imports and who will hold import access |
| Owners who must validate records | Each sales or service owner who checks their own accounts and opportunities adds review cycles, and disputes over ownership often extend timelines. | The number of validation owners, the review method and who signs off each batch |
| Pilot and parallel run | A pilot on one team's data and a parallel period with the spreadsheet still in use add test cycles, reconciliation work and a second round of corrections. | Whether a pilot and parallel run are included, their scope and the exit criteria for cutover |
| Integration needs | Connections to email, calendars or other systems add mapping, duplicate rules and testing, and may need official extensions or API users. | A list of connected systems, the direction of data flow and the authentication method planned for each |
What usually goes wrong with spreadsheet imports and how to prevent it
Most failed spreadsheet migrations are not caused by EspoCRM itself. They come from file preparation, re-runs, link errors and loose permissions on the Import tool. Each risk below has a preventive control you can put in place before the first production import.
Encoding errors that corrupt names
A file saved in a legacy encoding can turn accented names, currency symbols and punctuation into garbage characters that look valid on screen. Export your sheet as UTF-8 CSV and confirm the encoding before import. Run a test import of 20 to 50 rows and check names with diacritics, apostrophes and non-Latin scripts against the source sheet.
Duplicate accounts from re-runs
Running the same import twice in Create Only mode creates a second copy of every account. Choose a duplicate matching field such as an external customer ID or a normalized email domain, and use Create and Update mode for corrections. Review the count of created and updated records in the import log after every run.
Opportunities without a valid account
Opportunities imported before their accounts exist, or with account names that do not match exactly, load without a usable relation. Import accounts first, then contacts, then opportunities, and use the account ID column as the link key. Filter the opportunity list for records with an empty account after each stage.
Status values outside configured options
Spreadsheet stages such as "Closed Won!" or "Negotiation 2" rarely match the dropdown options configured in EspoCRM. Export the option list from the Entity Manager, map every spreadsheet value to an existing option, and reject rows with unmapped values before the file reaches production.
Over-broad Import access
The Import tool can create and change large numbers of records, so any user who holds it should be treated as privileged. Keep Import with administrators during the migration, grant it through a narrow role only to the named person running the load, and remove it afterward.
No tested revert path
A bad import that has not been rehearsed is difficult to undo under pressure. Take a database and file backup before every production run, test the revert function on a staging copy with the same file, and confirm that reverting a batch does not remove records created by daily users in the meantime.
Questions buyers ask before moving spreadsheets into EspoCRM
What does a spreadsheet to EspoCRM migration cost?
The cost depends on the size and state of the spreadsheets, the number of entities involved, and how much configuration EspoCRM needs before data arrives. Cost components are the discovery and field mapping work, the CSV preparation and cleansing, the import runs and checks, and any custom entities or layouts built first. Most of this is one-time. Recurring costs come from the EspoCRM hosting you choose and any official extensions you license. EspoCRM's open-source edition can be downloaded and self-hosted for free, according to the EspoCRM pricing page. Ask any quote to break out mapping, cleansing, import validation and post-go-live fixes separately, and to state what is excluded.
How long does moving spreadsheets into EspoCRM take?
Duration is driven by the number of sheets, how many records are duplicated or inconsistent, how many people must approve field decisions, and whether custom entities must exist before import. A single customer list with clean columns moves far faster than several linked sheets for accounts, contacts and opportunities that need relations set in order. Timing also depends on how quickly your data owners answer mapping questions. Ask for a plan with separate milestones for mapping sign-off, a trial import, full import and cleanup, so you can see which step controls the schedule.
What must our team provide before the import starts?
Your team must provide the spreadsheets, a named data owner for each entity, and written decisions on which columns map to which EspoCRM fields. Data owners need to confirm how duplicates are defined, which records are current, and who signs off the trial import. Sales and service leads should agree on the pipeline stages and opportunity fields that the CRM will use. Without these decisions, imported data will reflect old habits and need rework. Confirm the owners, sign-off dates and access to source files in the scope before work begins.
Can our internal team migrate spreadsheets to EspoCRM alone?
An internal team can do it alone if it has someone comfortable with CSV formatting, UTF-8 encoding, and the EspoCRM Import tool, plus an administrator who can run imports safely. The harder parts are usually relation ordering, duplicate matching and deciding what to do with inconsistent values, which need business input. Import access is itself privileged, so the team must decide who holds it. A partner can take on mapping, the trial runs and validation while your staff keep ownership of the data. Compare both options against the people, time and review capacity you have.
How do we revert a bad EspoCRM import?
EspoCRM's CSV import supports reverting imported records, so a bad run can be rolled back from the import results rather than edited by hand. Reverting is only a safe fallback if you check the first trial import carefully before running the full file, because records changed by later edits or other imports must be reviewed separately. Keep the original spreadsheets and a copy of the CSV files used for each run. Use Create Only for first loads and Update Only when refining existing records. Confirm the revert behavior on a test instance before relying on it in production.
Can EspoCRM hold personal data safely during migration?
EspoCRM can hold personal data safely only when the instance, access and transfer steps are controlled. Spreadsheets often sit in shared drives or personal inboxes, so the migration should remove those copies after the import is verified and restrict who can see the CSV files. The EspoCRM security documentation recommends enforcing a password policy, requiring two-factor authentication, avoiding admin accounts for daily work, and restricting access by IP address. Limit Import permissions to the people who need them. Ask your compliance and security leads to confirm retention and access rules before the data moves. DeployOpen prepares systems and evidence for compliance assessments but does not issue audit reports or certifications.
Which EspoCRM version and hosting should we plan for?
Plan the hosting and version before the import, because the supported PHP, database and web server combinations shape where the data lands. The EspoCRM server configuration documentation lists PHP 8.3 to 8.5, MySQL 8.0 or newer, MariaDB 10.6 or newer or PostgreSQL 15, on Apache, Nginx or IIS, with cron required for background jobs. Import of large files runs idle through cron, so a scheduled task must be working before you load data. Confirm the current release with the EspoCRM releases page and test on a staging instance first.
How DeployOpen works on this
DeployOpen plans, implements, tests, documents and supports self-hosted open-source platforms inside the client's own infrastructure. For a spreadsheet migration, that means we start from your actual sheets, agree the import order and matching rules in writing, and run every step in a test instance before production.
How we scope
- We review your current sheets, column definitions, owners and duplicate patterns before naming any deliverable.
- The written scope lists which entities, fields, relations and import modes are covered, and which sheets are excluded.
- Engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts.
How we build
- We prepare UTF-8 CSV files and mapping sheets, then import accounts, contacts and opportunities in dependency order.
- Duplicate matching fields and Create Only, Create and Update, or Update Only modes are tested on sample data first.
- Each test import is run against a non-production instance and checked record by record against the source sheets.
How we hand over
- You receive the field mapping, import order, duplicate rules and reversal steps as written documentation.
- Administrator and Import access are reviewed and limited to the people who need them, with the reasons recorded.
- We walk your team through the first live imports and the revert procedure so they can run the next batch themselves.
How we support
- Ongoing support, upgrades and continuous testing are available as a retainer after the migration closes.
- Support can cover recurring imports from new sheets, mapping changes and checks after EspoCRM upgrades.
- Ask us to confirm which support tasks the retainer includes before you sign, so responsibilities are clear.

