MigrationFox Docs

Teams to Teams (cross-tenant) migration

A reference for moving Microsoft Teams content between two Microsoft 365 tenants: teams, channels, channel messages with original timestamps, channel files on the backing SharePoint site, members, and guests. This page covers the credential shape on both sides, how the destination team is built in migration mode, how user identity is mapped across tenants, and the handling of private channels and embedded tenant-specific URLs.

Why cross-tenant Teams migration is special

Unlike a SharePoint or file-class migration, Teams chat history cannot be recreated by copying bytes. Microsoft's Teams Migration API is the only supported path that lets historical messages land with their original timestamps and sender. The destination team must be created in a special migration mode state, have the history written in, and then be flipped to the active state. MigrationFox drives that sequence end-to-end.

Supported scope

ItemCarried across?Notes
Team structure (name, description)YesCreated automatically, or you can pre-provision the destination team and point the job at it.
Standard channelsYesChannel names and descriptions are recreated. Ordering follows the source.
Private channelsYes, with caveatsSee Private channel migration.
Channel messagesYesOriginal timestamp and sender preserved through the Teams Migration API.
Files shared in channelsYesMigrated as companion SharePoint file jobs to the destination team's backing site.
Channel tabsPartialSee Tabs and apps.
Apps installed in the teamPartialMicrosoft-first apps (Planner, OneNote, Lists) are handled as part of the team; third-party app install state is not carried over.
Members and ownersYes, via user mappingMembers are added to the destination team after import mode completes.
Guest usersYes, with re-inviteSee Guest users and B2B.
Meeting history, recordings, 1:1 chatsNoOut of scope of the Teams Migration API. 1:1 chats stay with the source user; recordings live in each user's OneDrive (migrate per user via file migration).

Prerequisites

Both tenants

Azure AD app with Teamwork.Migrate.All

You need an Azure AD app registration on both the source and the destination tenant. The simplest approach is to reuse your MigrationFox Microsoft credential on each side.

Permissions (Application, not Delegated):

  • Teamwork.Migrate.All — required on the destination tenant to create teams in migration mode and import messages.
  • Team.ReadBasic.All, Channel.ReadBasic.All, ChannelMessage.Read.All — required on the source tenant to enumerate teams and read channel history.
  • Sites.ReadWrite.All — on both tenants, so channel files can move through each team's backing SharePoint site.

Admin consent must be granted on each tenant after adding the permissions. Delegated tokens are not accepted by the Teams Migration API — app-only is the only supported path.

User mapping

Source UPN → destination UPN

Source and destination tenants have different domains, so a given person has two different UPNs. Prepare a mapping list before running: john@source-company.comjohn@dest-company.com.

The wizard accepts the mapping as a CSV upload or a paste-in list. Unmapped senders fall back to a default imported-user identity, which is usually undesirable — fix the mapping up front. Unmapped members simply are not added to the destination team (no error, but review the report).

How the migration runs

  1. Source scan. MigrationFox enumerates the source team: channels, messages, members, tabs, and the backing SharePoint site.
  2. Destination provisioning. The wizard creates the destination team in migration mode (or attaches to a pre-provisioned team still in that state). Migration mode is the Microsoft-documented flag that allows writing messages with historical timestamps — a team in active state cannot accept backfilled history.
  3. Channel creation. Channels are recreated in the same order, with names and descriptions preserved.
  4. Message import. Messages are written through the Teams Migration API with their original sender (resolved from the mapping), original timestamp, and attachment references.
  5. File companion jobs. For each channel, the backing SharePoint folder is queued as a separate file migration job so attachments and shared documents land on the destination team's site.
  6. Complete migration. Once messages and files are imported, the team is flipped from migration mode to active. Members are added, and the team becomes usable.

URL rewriting in embedded links

Messages frequently contain links to files, SharePoint pages, and other Teams resources. Those links are tenant-scoped — they point at source-company.sharepoint.com or teams.microsoft.com/l/entity/... with a tenant ID in the path. If left untouched, those links would 404 or silently resolve against the wrong tenant after migration.

During message import MigrationFox rewrites tenant-host strings in message bodies to match the destination tenant where there is a 1:1 source-to-destination mapping:

External links (public websites, SaaS URLs not bound to the source tenant) are left as-is. Links pointing at resources that were not part of the migration (e.g. a SharePoint site that is not being moved) are also left as-is — they will still work cross-tenant only if guest access is configured for that resource.

Guest users and B2B conversion

Every team has members and guests. Members are in-tenant users; guests are external B2B identities from other tenants or consumer accounts.

Plan guest invites before you cut over

The simplest path: run a practice import, export the guest-invite list from the job report, bulk-invite those guests into the destination tenant in advance, then run the real migration. Guests with no invite on the destination side end up as orphan attribution rows — not broken, but a cosmetic problem.

Private channel migration

Private channels in Teams have their own SharePoint site (a separate site collection from the parent team's backing site). That means a private channel migration is effectively two operations joined together:

Membership of a private channel is a strict subset of team membership. The wizard preserves private-channel membership using the same UPN mapping; users who are not mapped are not added to the private channel and its message history still imports (with their source-side attribution resolved only if they appear in the mapping).

Tabs and apps

Known limits

Troubleshooting

SymptomLikely causeFix
Destination team cannot accept messages: “team not in migration mode” The team was switched to active too early, or an existing active team was targeted directly. Either create a new team through the wizard, or use the PowerShell cmdlet Microsoft provides to set an existing team back into migration mode. Active teams cannot be backfilled.
Messages import under a generic “imported-user” identity instead of the original sender Source UPN is not present in the user mapping, or destination UPN does not exist on the destination tenant. Export the mapping report from the job page, fix unmatched rows, and re-run on a fresh team. Already-imported messages keep the attribution they landed with.
Embedded SharePoint links in messages still point at the source tenant URL rewriting only rewrites host strings that have a direct mapping to the destination. Links pointing at sites that were not part of the migration are left alone. Either include those sites in a separate SharePoint migration, or accept that external-to-migration links will require guest access on the source tenant.
Guest users don't appear in the destination team after migration The external identities have not been B2B-invited into the destination tenant yet. Pull the guest re-invite list from the job report, run a B2B bulk invite on the destination tenant, then re-run the membership sync step.
Private channel imports but its files are missing Private channels store files in their own site collection. The companion file job runs against that separate site and can fail independently. Check the file companion job's status on the job detail page. Typical cause is missing Sites permission against the private channel's site URL.
HTTP 403 from the source tenant on /beta/teams/{id}/channels/{id}/messages The source app lacks ChannelMessage.Read.All, or admin consent was never granted. Add the permission in Azure AD, grant admin consent, wait a minute, rerun.
Team creation fails on the destination with “group already exists” A team with the same alias already exists on the destination tenant. Either rename the destination team in the wizard, or delete the orphan group on the destination before re-running.

Related