How to Migrate from TestRail: What Moves and What Stays Behind
Moving out of TestRail goes one of two ways. A file export (CSV, Excel or XML) carries the test case library and nothing else: no run history, no results, no attachments. An importer that reads TestRail's API can also bring milestones, runs and results with who tested what and when, but it needs the API switched on and an instance the importer can reach. Pick the route by one question: does the team need its execution history in the new tool, or only the cases? Then count what you have before you start, because the numbers you collect in TestRail are the only way to check the result afterwards.
What each route carries
TestRail offers three export formats for test cases from the Test Cases view: XML, CSV and Excel. CSV and Excel let you pick sections and columns and put separated steps on their own rows; XML has no options and, according to TestRail's own export documentation, keeps the original section and case structure. All three are exports of the case library. Runs, results and file attachments are not in them.
The third route skips files entirely. An API-based importer, whether a target vendor's wizard or a script you write, reads projects, suites, cases, milestones, runs and results straight from TestRail. This is the only route that moves execution history, and it is also the one with the most conditions attached.
| What you need to keep | CSV or Excel export | XML export | API-based importer |
|---|---|---|---|
| Cases, steps, expected results | Yes | Yes | Yes |
| Section hierarchy | As a column; survives only if the target importer rebuilds the tree from it | Yes, structure is kept | Yes |
| Custom field values | As columns; the target decides what they become | Depends on the target importer | Depends on the importer's field mapping |
| Milestones, runs, results, testers, dates | No | No | Yes, within the importer's limits |
| Images and files | No | No | Depends on the importer |
| Needs the API enabled and an internet-reachable instance | No | No | Yes |
A file export is the safe default when the library is what matters and the history can stay behind in a read-only TestRail. If anyone will ask "when did this last pass, and who ran it?" after the switch, you need the API route. The step-by-step mechanics of the file exports are in our guide to exporting test cases from TestRail.
Before you start: take an inventory in TestRail
Most migration problems are visible in TestRail before anything is moved. Spend this part of the day on the source, not the target.
Access and reachability
The API has to be enabled by a TestRail administrator under Admin > Site Settings > API, and each user generates an API key under My Settings (TestRail API introduction). Use an administrator's key if you can: a regular user's key may not see every project, the user list or shared steps, depending on permissions.
Check where the instance lives. TestRail Cloud is reachable from anywhere. A self-hosted TestRail Server behind a VPN is not, and a hosted importer cannot read it. In that case the realistic options are a script run from inside the network, a temporary firewall exception, or the file route.
On TestRail Cloud the API is rate limited: 180 requests per minute per instance on Professional and 300 on Enterprise, with a 429 response and a Retry-After header when you go over. TestRail Server has no built-in limit. A project with a few thousand runs means many thousands of requests, so on Cloud the history pull is usually what takes the time, not the cases.
The numbers to write down
Write these down per project. They are your acceptance criteria for the migration.
- Cases per suite, and the total.
- Custom case fields and custom result fields, with their types. Multi-select and dropdown fields are where mappings usually go wrong.
- Custom result statuses. TestRail ships with five system statuses; anything else your team added will need a home.
- Runs, including runs that live inside test plans, and the date of the oldest run anyone still looks at.
- Shared steps, and how many cases use them.
- Cases with very long steps or expected results, and cases whose evidence lives in non-image files (logs, HAR files, PDFs, videos).
- Where automation references TestRail case IDs: test titles, annotations, reporter configs, CI jobs.
Most of this comes out of the API in a few calls. The script below counts custom case fields, custom statuses and runs per project. It needs curl and jq, and it follows TestRail's pagination, which returns at most 250 records per page.
TR="https://yourcompany.testrail.io"
AUTH="[email protected]:YOUR_API_KEY"
api() { curl -s -u "$AUTH" -H "Content-Type: application/json" "$TR/index.php?/api/v2/$1"; }
echo "custom case fields: $(api get_case_fields | jq 'length')"
echo "custom statuses: $(api get_statuses | jq '[.[] | select(.is_system == false)] | length')"
# Runs per project. get_runs skips runs inside test plans; get_plans lists those.
for pid in $(api get_projects | jq '.projects[].id'); do
n=0; next="get_runs/$pid"
while [ -n "$next" ]; do
page=$(api "$next")
n=$((n + $(echo "$page" | jq '.runs | length')))
next=$(echo "$page" | jq -r '._links.next // empty' | sed 's|^/api/v2/||')
done
echo "project $pid: $n runs outside plans"
done
The custom field count is for the whole instance, so it is an upper bound per project. If a project's runs mostly live inside test plans, the run count from get_runs will look suspiciously small; repeat the loop with get_plans and .plans to see the rest.
Clean up before you move, not after
Migration is the cheapest moment to delete. Cases nobody has run in a year, suites for retired features and near-duplicate cases written by two people for the same flow all cost the same to move as useful ones, and they cost more afterwards because every one of them gets reviewed during the post-import check. If the library has grown by copy and paste, a duplicate review first pays for itself; the method is in how to find duplicate and low-quality test cases. Do the cleanup in TestRail so the counts you wrote down still describe what you are moving.
Running an API import: the QAM Hub wizard as a worked example
Every API importer makes the same decisions in a different order, so it helps to see one end to end. We build QAM Hub at QA Madness, and its TestRail importer is the one we can describe with exact limits. If you are evaluating another tool, ask its vendor the same questions this section answers.
The import starts from Import from other TMS on the organization's home page and is available on every plan to Organization Admins. It runs in six steps.
- Connect. TestRail URL, account email and API key, then Test connection. An optional Jira base URL turns TestRail case references into requirements linked to Jira and result defects into linked issues; without it the references still import as text. The API key is used only for this import and is deleted when it finishes.
- Choose. Each TestRail project becomes a separate project. Tick Import test runs and results to bring result history with testers, dates, assignments and defect links, and pick how far back: the 50 most recent runs (the recommended setting), the 200 most recent, or every run. Runs inside test plans import as ordinary runs. Import attachments brings images on cases and on results, up to five each, and makes the import noticeably slower.
- Review. Before anything is written you see counts per project for suites, sections, cases, milestones and runs, plus warnings. This is where custom fields get decided: each TestRail field can become a new field, go into Pre-conditions, become Priority, be appended to Steps or to Expected Result, or be skipped.
- Invite. TestRail users with an email address can be invited as Members (paid seats) or Viewers, with the remaining seats shown. The step is skipped when there is nobody new to invite.
- Import. It runs in the background and survives the dialog being closed.
- Report. Per project counts of suites, groups, cases, custom fields, tags, requirements, milestones, runs, results, custom statuses, attachments and linked issues, with warnings and errors, and a confirmation that the API key was deleted.
The limits that matter for planning: steps are split per step number and shared steps are inlined into each case; text fields hold up to 5,000 characters; up to 20 custom fields per project (5 on the Start plan); up to three TestRail custom result statuses become custom execution statuses on plans that have them; priority, type and estimate come across; labels become tags; references become requirements. An import that would exceed the plan's limits is refused before it starts, a project that fails is removed completely while the others in the same import stay, only one import runs per organization at a time, and importing the same project again creates a second copy instead of updating the first.
The step-by-step help with screenshots is in the knowledge base article on importing from TestRail, and the feature summary is on TestRail migration. On the Advanced plan the import and field mapping can be done together with the QA Madness team; plan differences are in plans, seats and what each plan includes.
What does not come across, and what to do about each gap
No route moves everything. The migrations that go badly are the ones where the gaps are discovered in week three by someone looking for a file. List them now and decide each one on purpose.
Files that are not images
Logs, HAR files, PDFs, spreadsheets and videos attached to cases or results do not come through file exports at all, and many API importers, ours included, move only images. Three ways to handle it, in order of effort. Keep TestRail read-only for as long as an audit or a customer could ask for that evidence, and link to it. Re-attach files by hand only for cases that are still active and where the file is the test data, such as an upload fixture. Or script a download of the attachments through the API into storage your team controls, keyed by TestRail case ID, if the evidence has to outlive the TestRail subscription. Pick one before the import, because the third option is far easier while the TestRail account is still paid for.
Old run history
Bringing every run sounds safest and is rarely needed. Ask who uses history and for what. Flakiness and stability questions look at recent runs. Audits look at specific releases. A defect investigation looks at one case. If nobody can name a question that needs runs from two years ago, a recent window is enough and the import finishes sooner. The runs you leave behind stay readable in TestRail as long as the account exists, so export run reports for any release you are obliged to keep before you cancel.
Custom fields that do not fit
Every target tool has its own field model and limits, so some TestRail fields will not map one to one. Decide per field. Fields that nobody filters or reports on can be appended to the steps or preconditions as text, which keeps the information without spending a field slot. Fields that drive reports need a real field. Fields that were created for one project years ago and are empty on most cases can be dropped. Writing this decision down per field before the import is what stops the mapping step from turning into guesswork.
Custom result statuses
If your team added statuses such as Not applicable, Deferred or Known issue, find out how the target counts them before you rely on old pass rates. A status that counted as neither pass nor fail in TestRail but becomes Untested or Failed in the new tool changes every historical report. Where the target allows fewer custom statuses than you have, merge the rarely used ones in TestRail first so you choose the mapping, not the importer.
Test plans and configurations
TestRail groups runs into test plans, often one run per configuration such as browser and operating system. Most tools have no exact equivalent. In QAM Hub the runs inside a plan arrive as ordinary runs; group them under a milestone afterwards if the plan was how the team read release status. If configurations matter for reporting, check that the run names carry the configuration before you import, because the name may be the only place it survives.
Shared steps
An importer that inlines shared steps keeps every case readable but turns one editable block into many copies. If a shared login sequence was used by two hundred cases, a later change to login means two hundred edits or a template. Find the heavily used shared steps in your inventory and decide whether to rebuild them as a template or a precondition in the new tool.
Case IDs used by automation
This is the gap teams find last. Automated tests often carry TestRail case IDs in their titles or annotations so that a reporter can post results to the right case. After migration the cases have new IDs, and every result posted with the old ID either fails or lands nowhere. Search the automation repositories for the TestRail ID pattern before you switch, keep a mapping from old IDs to new ones (the import report and a CSV export of the new library give you both sides), and change the IDs in code in the same release that switches the reporter. How result mapping works on the QAM Hub side is described in mapping automated test results to test cases and in the test case ID glossary entry.
Things nobody migrates
Saved filters, dashboards and report templates, user roles and permission groups, and integrations with Jira and CI all have to be set up again in the new tool. They are quick to rebuild and slow to remember, so list the ones in daily use during the inventory.
Checking the result
Use the numbers you wrote down. Compare case counts per suite, custom fields, statuses and run counts with the import report. A mismatch is not automatically a failure, because limits you chose (a run window, skipped fields) explain some of it, but each difference should have a reason you can state.
Then check by hand, deliberately picking the awkward cases rather than random ones:
- the case with the longest steps, to see whether anything was cut at a field limit;
- a case that used shared steps;
- a case with a custom multi-select or dropdown field;
- a case with a long execution history, to confirm testers, dates and statuses on old results;
- a result that had a defect link, to see whether it points at the right ticket;
- a case in the deepest section, to confirm the tree.
Keep TestRail read-only, not cancelled, until at least one full release has been tested in the new tool. The first release is when people look for something specific and find out whether it moved.
When a CSV import is the better route
The API route is not always the right one. A file export and a CSV import are the better choice when the instance cannot be reached from outside the network and opening it is not an option; when the team wants a deliberately fresh start with a curated subset of cases and no history; when you are trialling a tool on one suite before committing; or when you are moving from TestRail and another source at once and want one consistent import format. In QAM Hub the CSV import covers test cases, checklists and requirements, described in CSV import and export. The trade-off is the one in the table above: you get the library and lose the history.
Where to spend the effort
Spend most of it on the inventory and the gap decisions. The import itself is the short part whichever tool you choose; the work that decides whether the migration is remembered as easy is knowing what you had, choosing what to leave behind, and checking the awkward cases before the team depends on the new tool. If the decision about where to go is still open, our TestRail alternatives roundup and the QAM Hub vs TestRail comparison cover that question, and what a test management system should do is a reasonable checklist for any target.