Recommended: JavaScript SDK for React Native
The JavaScript SDK is now the default and recommended way to build React Native apps with Dynamic. If you are starting a new app, see the React Native Quickstart (JS SDK). This guide is for migrating an existing legacy React Native SDK app.
Who this is for
You’re moving a React Native app from the legacy SDK (@dynamic-labs/legacy-client + @dynamic-labs/legacy-react-native-extension) to the headless JavaScript SDK (@dynamic-labs-sdk/*). The same JavaScript SDK packages run on web and React Native, so the migration is mostly a shift from a webview-based, UI-heavy SDK to a headless, function-based one.
The JavaScript SDK is headless: it gives you functions and React hooks for auth, wallets, and money movement, and you build every screen. The legacy SDK shipped a built-in WebView UI and orchestrated flows for you.
The big shifts
- No built-in UI.
client.ui.*, the Dynamic WebView widget, and all modals are gone. You render every screen. - No
ReactNativeExtensionor webview URL. UsecreateDynamicClientexactly as on web. - Extensions are added separately, not chained.
createClient().extend(ReactNativeExtension()).extend(ViemExtension())becomescreateDynamicClient()followed byaddEvmExtension(),addSolanaExtension(), etc. - React hooks return a TanStack Query result. Destructure
.data, e.g.const { data: user } = useUser(). - Events are for ambient state, not flow outcomes. Old
client.<area>.on/offbecomesonEvent/useOnEvent. - External wallets connect through WalletConnect. There is no built-in wallet list; you build it and deep-link users to wallet apps.
- Post-login setup is explicit. WaaS wallet creation, MFA, and device registration no longer happen automatically.
- Native-specific setup is small. Polyfills, deep-link schemes, and the WalletConnect native shim are the main additions. See React Native Setup for details, then Expo or Bare React Native depending on how your app is built.
Type renames
Client initialization
Legacy SDK
JavaScript SDK
addWalletConnectEvmExtension() / addWalletConnectSolanaExtension() from the respective /wallet-connect subpaths. See Authenticate with WalletConnect.
In React, wrap the app with <QueryClientProvider> then <DynamicProvider client={dynamicClient}>:
Reading state
Events to promises
The legacy SDK was event-driven: you subscribed toonAuthSuccess, onWalletAdded, etc. The JavaScript SDK is imperative — you await the function or use a hook’s onSuccess/onError. Events still exist for ambient changes (wallet list changes, session expiry), but they are not how you observe an action you started.
Connecting external wallets
The legacy SDK rendered a “Connect Wallet” list inside the WebView. The JavaScript SDK ships no connect UI, so you build the list. On React Native, external wallets are reached through WalletConnect deep links (or QR on tablet/desktop).- Expo
- Bare React Native
connectAndVerifyWithWalletConnectEvm over a deep link is not supported on React Native because iOS blocks a second deeplink not tied to a user gesture. For deeplink connections, call connectWithWalletConnectEvm first, then verify the account from a separate user tap with verifyWalletAccount. QR-based connectAndVerify works.walletConnectUserActionRequested handling.
API mapping
Client and extensions
Authentication
All new functions are from@dynamic-labs-sdk/client unless noted.
OTP is stateless now.
sendEmailOTP and sendSmsOTP return an otpVerification object; pass it to verifyOTP along with the user’s code as verificationToken.updateUser({ userFields }) may return an OTPVerification if the changed email or phone requires verification. Hold it and finish with verifyOTP.MFA and step-up authentication
Device registration
Wallets
WaaS (embedded wallets)
From@dynamic-labs-sdk/client/waas unless noted.
<ExportPrivateKey /> renders the key in a sandboxed WebView and never exposes it to JS. It fills the container you size, so give it a real height (for example, inside a flex-1 Modal).Chains
Gaps and changed APIs
A small number of legacy APIs have no direct equivalent in the headless SDK. In most cases you replace them with a combination of available functions or remove the feature.Version and dependency notes
- Keep all
@dynamic-labs-sdk/*packages on the same minor version. - WalletConnect on React Native needs
@walletconnect/react-native-compat(Expo:npx expo install @walletconnect/react-native-compat; bare: also install@react-native-community/netinfo). Import it as the first line of your polyfills file. - Passkeys need
react-native-passkeyand platform-specific configuration. See Passkeys on React Native.
Next steps
- React Native Setup — polyfills, native modules, and deep links
- Expo / Bare React Native — build-specific setup
- React Native Quickstart (JS SDK) — a complete Expo + email + EVM example
- Adding Extensions — enable the chains you support
- Authenticate with WalletConnect — external wallet flow on mobile
- Passkeys on React Native — platform configuration for passkeys
- Business Accounts on React Native — multi-party account specifics
- Creating a Dynamic Client
- Initializing the Dynamic Client