# Migrate from Sendbird

The web pack and every platform pack can migrate an existing Sendbird chat app to Stream. The migration has two halves: a **code migration** that swaps the Sendbird SDK for Stream Chat inside your app, and an optional **data migration** that moves your users, channels, and message history (including reactions) afterwards. The code migration is platform-specific and lives in each pack; the data migration is server-side and language-agnostic, so it's shared by all of them.

## Start a migration

Describe the task to the router, or invoke your platform's pack directly:

```bash
/stream migrate my iOS app from Sendbird to Stream
/stream-react we're switching off Sendbird, replace it with Stream Chat
/stream-android migrate my Sendbird chat integration to Stream
```

The router picks the pack from the platform signal in your prompt or project files, installing it on demand if needed (the Flutter pack asks for a confirmation first). Name your platform in the prompt, or run from the project directory: with no platform signal at all, the router defaults to the web pack.

| Platform                      | Skill                  | Migrates                                                                                                                                                                        |
| ----------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| React / Next.js (web)         | `/stream-react`        | `@sendbird/chat` + `@sendbird/uikit-react` → `stream-chat` + `stream-chat-react`                                                                                                |
| iOS (Swift / SwiftUI / UIKit) | `/stream-swift`        | Sendbird Chat SDK / UIKit / SwiftUI → `StreamChat` + `StreamChatSwiftUI` or `StreamChatUI` (your choice, not the source's)                                                      |
| Android (Kotlin)              | `/stream-android`      | Sendbird Chat SDK / UIKit (Compose or XML) → Stream Chat Compose, or `stream-chat-android-client` alone when the app draws its own UI                                           |
| React Native / Expo           | `/stream-react-native` | `@sendbird/chat` + `@sendbird/uikit-react-native` → `stream-chat` + `stream-chat-react-native` / `stream-chat-expo`, or `stream-chat` alone when the app has its own components |
| Flutter                       | `/stream-flutter`      | `sendbird_chat_sdk` / `sendbird_uikit` → `stream_chat_flutter` / `stream_chat_flutter_core`                                                                                     |

## How the code migration works

The runbooks don't assume your integration has any particular shape. The first step is always detection: the pack maps the Sendbird footprint and classifies each touchpoint (a UIKit drop-in, a wrapper or service layer, custom hooks, a store with reducers, or direct SDK calls scattered through the code) and migrates each one per its pattern. From there, four principles shape the work:

- **Migrate in place, change as little as possible.** On every platform, the pack preserves your architecture, navigation, and public APIs, and swaps what's inside each SDK touchpoint. Callers don't change.
- **No find-and-replace.** Separate audits of the web and React Native SDK pairs each found that under 2% of symbol pairs survive a mechanical rename; nearly every touchpoint shifts shape or behavior. The web and React Native packs carry compile-checked mapping tables and a catalog of the behavioral traps that produce silent runtime bugs when ported one-to-one (message echo semantics, mute vs. ban, cursor pagination); the native packs carry per-area mapping tables inline.
- **Nothing is dropped silently.** The web and React Native packs build a parity ledger of every user-facing chat feature before the first edit, and every row must end as ported, rewritten, or explicitly decided. The native packs enforce the same rule per screen: every screen the original exposed is either wired to a Stream equivalent or surfaced to you, never quietly dropped.
- **The app must look the same.** Before the original UI is deleted, the pack captures a visual baseline of the running original (screenshots and driven states, plus measured CSS values on the web, where there's a DOM to probe) and verifies the migrated app against it with fresh captures, never from code review alone.

Verification is gated, not declared. On web and React Native that's an ordered set of gates: type checks, a clean build, a check that the Sendbird packages are really gone, a two-user runtime smoke test over a real connection, the design comparison, ledger closure, and docs that match what the migrated app actually does. The native packs gate on a per-screen design and behavior comparison against the captured baseline, plus a clean build.

### It checks in before big decisions

Some Sendbird features have no direct Stream equivalent (scheduled messages, or an offline cache on web, for example). Those are product decisions, so no pack decides them silently; the native packs ask as decisions come up rather than guess. The web and React Native packs formalize this as a checkpoint: when the ledger contains a gap, or credentials or the design bar are unresolved, they pause and present the migration plan before the first edit, asking everything in one batched round. When nothing needs your input they proceed and include the plan in the final summary, and in a non-interactive run they don't stall: they take the documented default for each gap, mark it provisional, and call it out in the final report.

### Credentials

Sendbird lets you connect with just a user id and treats tokens as optional; Stream always requires a signed token, so every runbook wires a token path early. The web and React Native packs use credentials you provide (or that already exist in the project), fall back to `getstream init` only when there are none, and prove a real connection end-to-end before migrating any UI. The native packs ask once, up front, whether to mint the key and token via the CLI or take a pasted pair.

## Migrating your data

The code migration leaves the app pointing at an empty Stream app: no history has moved. Once the code migration is verified, the pack asks whether to migrate the data too. If you say yes, it hands off to the shared runbook, which walks the [official migration guide](https://getstream.io/chat/docs/node/migrating-from-sendbird/) with you:

1. **Pick a strategy.** A hard switch (simplest, needs a maintenance window), uni-directional sync (zero downtime, the most common choice), or bi-directional sync (zero downtime, no forced app update, the most complex). Both sync strategies rely on Stream's real-time Sendbird sync, which is available on Enterprise plans and enabled by Stream support.
2. **Export from Sendbird** via the Sendbird Platform API.
3. **Build and validate the import file**: a JSONL file mapping Sendbird objects to Stream's [import format](https://getstream.io/chat/docs/node/import/), including the Sendbird-side transforms the import docs don't cover (`channel_url` values that overflow Stream's 64-character channel id limit, epoch-millisecond timestamps that must become RFC3339, and Sendbird's aggregated reactions, which must be split into one Stream reaction row per user).
4. **Import via the `getstream` CLI**, starting with a tiny trial import before the full run.
5. **For the sync strategies**, mirror new Sendbird activity into Stream through Stream's built-in Sendbird webhook support until cutover.

<Admonition type="warning">

The data migration touches production data, and copying attachments to Stream's CDN can incur transfer cost, so no skill ever starts it unsolicited: it always asks first. Skipping it is fine, since the code migration is complete on its own.

</Admonition>


---

This page was last updated at 2026-08-06T11:48:18.711Z.

For the most recent version of this documentation, visit [https://getstream.io/agent-skills/docs/migrate-from-sendbird/](https://getstream.io/agent-skills/docs/migrate-from-sendbird/).