Skip to content
SharePoint Development

Term Store at the limit: Taxonomy migration into a shared SharePoint Online tenant

Millions of terms from SharePoint 2016 meet the 1-million-term limit of the SharePoint Online Term Store. How we transformed managed metadata into text, choice and lookup fields, including wire-format pitfalls and fallback mapping.

On-premises, the Term Store felt almost unlimited, so it was used that way. In our migration project (series starts with part 1), each major project had its own term sets: spatial asset structures, material catalogs, plant hierarchies, project organization. Multiplied across 130+ projects, this produced millions of terms.

SharePoint Online sets a hard boundary: 1 million terms per Term Store, tenant-wide. And this tenant does not belong to one project or even one department. It belongs to the entire group. The old architecture where every project brings its own taxonomy failed in the cloud before the migration even started.

The problem is bigger than the limit

Even if the limit were higher, structural reasons still speak against a one-to-one takeover:

  • Shared tenant means shared governance. A Term Store used by ten group areas cannot tolerate project-specific term sprawl. Every term is tenant-wide infrastructure.
  • Lookup lists are not an escape route. The historical twin of taxonomy, very large lookup lists, hits its own SharePoint Online limits: List View Threshold and the number of lookup columns per query. Moving taxonomy into lookups simply trades one limit for two.
  • Queryability. Terms used by exactly one project do not provide group-wide value. They are project-local data and should be stored that way.

Our target architecture

We classified fields by their actual usage pattern:

Usage pattern in the sourceTarget type in SharePoint Online
Group-wide shared vocabulary, such as document classesManaged Metadata with one global consolidated term set
Project-local structure values such as locations or assetsText/Note fields with normalized values
Small, stable value setsChoice fields
Project-local reference data with relationship semanticsLookup to lean project-local lists

The principle: only what is maintained group-wide belongs into the Term Store. Everything else is transformed during migration.

The technical side: changing field type during import

Moving a taxonomy field into a text field sounds trivial. It is not. SharePoint stores taxonomy values in a wire format that becomes garbage in the target if copied naively:

-1;#Central Station|a1b2c3d4-e5f6-7890-abcd-ef1234567890

If you write that unfiltered into a text field, users see GUID suffixes and ;# prefixes in the UI. Our transformation engine therefore normalizes every value by type:

// Taxonomy wire format -> clean text value
// "-1;#Central Station|a1b2..." -> "Central Station"
// Multi-value: extract all labels, discard GUIDs
static string TaxonomyToText(string wireValue) =>
    string.Join("; ",
        WireEntries(wireValue)              // split at ";#" pairs
            .Select(e => e.LabelBeforePipe()) // cut "|<guid>" suffix
            .Where(l => !string.IsNullOrWhiteSpace(l)));

Two traps we only found in live operation:

  1. Passthrough holes: note and choice fields that historically contained raw taxonomy values were initially passed through unfiltered. The GUID garbage only became visible in the target. Normalization must apply to all target types, not only the obvious taxonomy transformations.
  2. The parity check must speak the same normalization language: if source and target are compared without canonicalizing ID;# prefixes and |guid suffixes, you create hundreds of false positive differences and lose trust in your own acceptance tool. Transformation and comparison logic belong into the same shared code.

Consolidation with fallback: document-class mapping

The group-wide term set for document classes had to be consolidated from dozens of historical variants: name drift over ten years, project-specific special cases and renamed terms. Our mapping works as a rule chain:

Source value
  │ 1. exact match in target term set?        -> target term (by GUID)
  │ 2. hit in synonym/history table?          -> mapped target term + log
  │ 3. hit after normalization?               -> mapped target term + log
  └ 4. no hit                                 -> fallback term + remediation register

The decisive point is not the chain itself, but its auditability. Every fallback goes into a register that the business team can work through by project after migration. “Unresolved” is a state with an owner and a list, not a silent data hole.

For values that remain taxonomy values, the Migration API manifest also needs real term GUIDs from the target term set. Label-based mapping is not enough, otherwise the import worker creates orphaned labels. We cover this in more detail in part 3 about the Migration API.

What we recommend today

  1. Measure term usage before migrating. A term set with 200,000 terms, of which 1,900 were ever used, is not a migration candidate. It is a cleanup candidate.
  2. Decide field type per field, not per original field type. “All taxonomy becomes text” is just as wrong as “everything remains taxonomy”.
  3. Take wire formats seriously. ;# and |guid artifacts are the most common source of “broken metadata” after field type transformations.
  4. Plan the mapping protocol as an acceptance artifact. The business team never asks “did you map?” They ask “what exactly did you map where, and what do we still need to clean up?”

Your Term Store is overflowing, your lookup lists too, and the group tenant has its own rules? We built exactly this transformation at 25 TB scale. We can help, from taxonomy analysis to auditable mapping.

All parts of the series:

  1. Why not a one-to-one migration
  2. 25 TB SharePoint migration: Why standard tools are not enough
  3. The SharePoint Migration API in practice
  4. Term Store at the limit: Taxonomy migration in a shared tenant (this article)
  5. Migrate SharePoint version history intelligently
  6. Provisioning at enterprise scale: PnP, throttling, permissions
  • Taxonomy
  • Managed Metadata
  • Term Store
  • SharePoint Online
  • Migration
  • Metadata

Questions about this topic?

We are happy to help you put this into practice in your environment.