Slack to Teams migration
Bring Slack channels, their messages and thread replies, and files shared in those channels into a new Microsoft Teams team, with original message dates. This guide covers the connections on both sides, the wizard flow, user mapping, and the Slack and Microsoft limits that shape what comes across.
Before you start
MigrationFox moves Slack channels (public and private) into Microsoft Teams. Direct messages (1:1) and group DMs are not migrated, and Slack to Google Chat is not supported. Each migration creates a new team in Microsoft Teams; it doesn't import into an existing team. Messages are copied as plain text.
What this migration carries across
- Channels: each selected Slack channel becomes a channel in the new team, with the same name. Public channels become standard channels; private channels become private channels. In the Windows app you can rename individual channels before you start.
- Messages: message text is imported with its original date through Microsoft's Teams import API. When the sender's email maps to an account in the destination tenant, the message is posted as that person. When it doesn't, the message is posted with the original name and email in brackets at the top (for example
[Jane Doe (jane@example.com)]). Slack join/leave notices are skipped. - Thread replies: with Include thread replies on (the default), replies are imported under their parent message.
- Files shared in channels: with Also migrate channel files on, files attached to the migrated messages are downloaded from Slack and uploaded to the new team's document library. This option is off by default.
- Team members: after the import, workspace members are added to the new team through your user mapping. Slack workspace owners and admins become team owners; everyone else becomes a member.
What does not migrate
- Direct messages and group DMs: only channels are read.
- Formatting and mentions: messages are copied as plain text. Slack formatting, @mentions, channel links and emoji codes are not converted, so they appear as Slack wrote them in the raw message text.
- Emoji reactions: not copied.
- Slack apps, bots, Workflow Builder flows and incoming webhooks: recreate these on the Teams side after the migration.
- Slack Connect (shared external channels): external participants need to be invited to Teams as guests. Guests are not added to the new team automatically.
Prerequisites
Your own Slack app and its bot token
MigrationFox connects to Slack with a bot token (it starts with xoxb-) from a Slack app you create in your workspace. There is no Slack sign-in button.
- Go to api.slack.com/apps → Create New App → From scratch. Name it and pick your workspace.
- Open OAuth & Permissions and add these Bot Token Scopes:
channels:read,channels:history: list and read public channelsgroups:read,groups:history: list and read private channelsusers:read,users:read.email: resolve members and their emails for user mappingfiles:read: download files shared in channels
- Click Install to Workspace and authorize. Then copy the Bot User OAuth Token.
- Add the app to every channel you want to migrate (for example with
/invite @YourAppNamein the channel). Slack only lets a bot read the history of channels it is a member of, and private channels are only listed once the app has been added.
In MigrationFox, open your project's Connect tab, click Slack, and paste the token into Bot User OAuth Token. MigrationFox checks the token with Slack when you save it. The scopes above are read-only; MigrationFox doesn't write to Slack.
A Teams connection to the destination tenant
On the Connect tab, click Teams and choose one of:
- Connect with admin consent: a Global Administrator of the destination tenant approves the MigrationFox Teams app once. No Azure setup, nothing to copy.
- Bring your own Azure app: your organization's own app registration (client ID, secret and tenant ID), for security teams that won't approve a third-party app.
Microsoft's import API only accepts application permissions, so a Teams connection is always tenant-wide. Your own app needs the same Application permissions as the MigrationFox Teams app, with admin consent granted: Teamwork.Migrate.All, ChannelMessage.Read.All, Channel.ReadBasic.All, Team.ReadBasic.All, TeamMember.Read.All, TeamMember.ReadWrite.All, User.Read.All, Group.ReadWrite.All, Sites.ReadWrite.All.
Slack to Teams only writes to Teams, so it doesn't depend on Microsoft's separate approval for reading Teams messages (that approval affects Teams as a source).
Slack member email → Microsoft 365 account
Teams needs a real destination account (for example jane@contoso.com) to show a message as written by that person and to add them to the team. The wizard's Users step lists Slack members and matches them to destination accounts by email automatically.
If emails differ between Slack and Microsoft 365, upload a CSV with the columns sourceEmail and destEmail (optional: sourceDisplayName, destDisplayName). Leave destEmail empty to skip a person. With Skip unmatched users off, people without a match are mapped to the same email address. Fix the mapping before you run: messages already imported keep the author they landed with.
Wizard flow
In your project, open the Migrate tab and click Start on Teams & chat. The same wizard is in the MigrationFox Windows app under Teams & chat.
- Source. Choose Slack → Teams and your Slack connection.
- Teams. Select the workspace, open it, and pick the channels to migrate. You can change the destination team name here.
- Destination. Pick the Microsoft Teams connection, check the team mapping, and set Also migrate channel files and Include thread replies.
- Users. Review automatic matches, upload a mapping CSV if needed, and decide whether to skip unmatched users.
- Review. Confirm and launch. Progress shows on the project's Migrate tab.
How the destination team is built
- A new team is created in Microsoft's migration mode, which is what allows messages to keep their original dates.
- For each selected channel, a matching channel is created (the team's built-in General channel is reused for a channel named “general”).
- Messages are imported, then thread replies under their parents. A message that fails is logged and the rest continue; a channel that fails doesn't stop the other channels.
- Each channel and then the team are taken out of migration mode, so the team becomes a normal, usable team.
- Members and owners are added through the user mapping. The log lists anyone who couldn't be found at the destination or had no mapping.
- If Also migrate channel files is on, shared files are downloaded from Slack and uploaded to the team's document library.
Known limits
Slack free plan: limited visible history
On Slack's free plan, older messages are hidden from the workspace and Slack's API doesn't return them, even to an admin's app. Only what Slack still shows can be migrated. If most of your history is missing after a run, check your Slack plan first.
- The app must be in each channel. Channels the Slack app hasn't been added to can't be read. Private channels don't appear in the channel list until the app is added.
- Plain text only. Formatting, mentions and emoji codes are not converted.
- Reactions are not copied.
- Message dates. Microsoft's import only accepts messages dated after the team's start date. MigrationFox creates the new team with a start date of January 1, 2000, well before any Slack history, so older messages keep their original dates. Any message that still fails to import is recorded in the migration's log.
- New team every run. Running the same channels again creates another team. Delete test teams in the Teams admin center when you're done.
- Slack Connect channels and guests: external people must be invited as guests on the Teams side.
- Slack apps and integrations don't carry over. Rebuild them with Power Automate, Teams apps, or incoming webhooks.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| “No channels found”, or far fewer channels than the workspace has | The Slack app is missing channels:read / groups:read, or it hasn't been added to the channels (private channels only show once the app is a member). |
Check the Bot Token Scopes, reinstall the app if you changed scopes, and add the app to the channels you need. |
| A channel is listed but its messages fail to load | The app isn't a member of that channel, or channels:history / groups:history is missing. |
Add the app to the channel (/invite @YourAppName) and confirm the history scopes. |
| Older messages are missing | Slack's free plan hides older history from the API. | Check your Slack plan before migrating. Check the migration's log for messages Microsoft rejected. |
Messages show [Name (email)] at the top instead of appearing as the person |
That sender's email had no match in the user mapping, or the mapped account doesn't exist in the destination tenant. | Fix the mapping and run again into a new team. Messages already imported keep the author they landed with. |
| HTTP 403 when the team or channels are created | Admin consent wasn't granted, was granted in a different tenant, or your own app is missing a permission (for example Teamwork.Migrate.All or Group.ReadWrite.All). |
Have a Global Administrator of the destination tenant reconnect with admin consent, or add the missing Application permission to your app and grant admin consent. |
| Files don't appear in the team's Files | Also migrate channel files was off, or some uploads failed. | Check the migration's log for the “Uploaded N/M Slack files” line. Turn the option on for the next run. |
| Some people aren't in the new team | They had no mapping, weren't found at the destination, or are guests. | The log lists who was skipped. Add them in Teams, or fix the mapping for the next run. |
Related
- Teams to Teams migration: the same Teams import API, with Microsoft Teams as the source
- SharePoint Site Migration: the SharePoint site behind each team holds its files