
Clerk Compatibility in Expo 54 and 55
What does Clerk support in Expo SDK 54 and 55?
@clerk/expo v3.1.x provides comprehensive support for Expo SDK 54 and 55, including the New Architecture and multiple authentication approaches. Part 1 of this two-part series covers version requirements, architecture integration, Expo Go constraints, and core authentication methods (Google, Apple, SSO, Passkeys, and Biometric).
@clerk/expo v3.1.x fully supports both Expo SDK 54 and Expo SDK 55 for iOS and Android. This article provides a comprehensive compatibility reference for developers integrating Clerk authentication into Expo apps, covering version requirements, authentication approaches, feature availability, setup configuration, and known limitations. All information reflects @clerk/expo v3.1.12, Expo SDK 54, and Expo SDK 55 as of April 2026.
Clerk and Expo Compatibility: Version Support Matrix
The @clerk/expo SDK v3.1.x is compatible with both Expo SDK 54 and Expo SDK 55. The following table summarizes the version requirements for each component.
The @clerk/expo package declares the following peer dependencies: expo: >=53 <56, react: ^18 || ^19, and react-native: >=0.73. The minimum Node.js requirement is 20.9.0.
All three Clerk authentication approaches work on both SDK versions. The primary differences between SDK 54 and SDK 55 are:
- SDK 54 supports both the Legacy Architecture and the New Architecture. It is the last SDK to support the Legacy Architecture.
- SDK 55 requires the New Architecture. The
newArchEnabledconfiguration option has been removed.
Passkeys are supported on both SDK versions — @clerk/expo-passkeys declares a peer dependency of expo: >=53 <57 (as of v1.1.0), which includes both SDK 54 and SDK 55.
How Clerk Integrates with Expo
Architecture Overview
The @clerk/expo package builds on top of @clerk/react, which wraps ClerkJS — the core JavaScript SDK. When you add <ClerkProvider> to your Expo app, it initializes the authentication context and connects to Clerk's Frontend API (FAPI) using your publishable key.
Clerk uses a hybrid stateful and stateless session model. Each session is stored in Clerk's database and represented on the client as a short-lived JSON Web Token (JWT) with a 60-second expiry. The SDK automatically refreshes this token on a 50-second interval, ensuring uninterrupted access without manual token management.
In Expo apps, token persistence is handled via the tokenCache prop on <ClerkProvider>. Using expo-secure-store, tokens are encrypted and stored on the device — in Apple Keychain on iOS and Android Keystore on Android. Without tokenCache, tokens are stored in memory and lost when the app restarts.
The publishable key (environment variable EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY) identifies your application and encodes the FAPI URL. This key must be explicitly passed as a prop to <ClerkProvider> in Expo because React Native production builds do not inline environment variables the same way web bundlers do.
Three Approaches to Clerk Authentication in Expo
Clerk organizes Expo authentication into three approaches, each adding capability and requiring more native integration.
Approach 1: JavaScript Custom Flows
JavaScript custom flows use only JavaScript-based authentication with no native module dependencies. This includes email/password sign-in and sign-up, phone verification via OTP, magic links (email links), and passwordless login. The relevant hooks are useSignIn(), useSignUp(), useAuth(), useUser(), and useSession().
JavaScript custom flows work in both Expo Go and development builds. This approach is suitable for rapid prototyping and for providers that do not have native SDKs.
Approach 2: JavaScript + Native Sign-In Hooks
This approach adds native platform integration for specific authentication methods:
- Native Google Sign-In via
useSignInWithGoogle(from@clerk/expo/google) — uses the platform's system credential picker (ASAuthorization on iOS, Credential Manager on Android) without browser redirects - Native Apple Sign-In via
useSignInWithApple(from@clerk/expo/apple) — uses Apple's native authentication UI on iOS - SSO/OAuth via
useSSO()— browser-based social login supporting 31+ providers, requiring a custom URL scheme for redirects - Biometric authentication via
useLocalCredentials(from@clerk/expo/local-credentials) — stores password credentials with biometric unlock
Approach 2 requires development builds and does not work in Expo Go because Expo Go cannot load custom native modules or register custom URL schemes.
Approach 3: Native Components (Beta)
Native components render fully native UI using SwiftUI on iOS (via the clerk-ios SDK) and Jetpack Compose on Android (via the clerk-android SDK). Three components are available:
<AuthView />— complete sign-in/sign-up UI that automatically handles all authentication methods enabled in the Clerk Dashboard<UserButton />— avatar that opens a native profile modal on tap<UserProfileView />— inline profile management (email, phone, MFA, passkeys, sessions, connected accounts)
Native components were released in beta on March 9, 2026 as part of @clerk/expo v3.1.0. They require development builds and the @clerk/expo plugin in app.json. Approach 1 and Approach 2 remain the production-stable options.
Expo SDK 54 Compatibility
Expo 54 at a Glance
Expo SDK 54 was released on September 10, 2025. It ships React Native 0.81 and React 19.1.
SDK 54 is the last SDK version to support the Legacy Architecture. Both the Legacy Architecture and the New Architecture work in SDK 54. At the time of SDK 54's release, approximately 75% of projects on EAS Build were already using the New Architecture.
Key platform changes in SDK 54:
- Precompiled XCFrameworks for faster iOS builds — clean build times dropped from approximately 120 seconds to approximately 10 seconds on M4 Max hardware
- Rebuilt
expo-dev-launcherwith improved debugging capabilities - Android 16 / API 36 is the default
targetSdkVersion, making edge-to-edge display mandatory - Minimum Xcode 16.1 required (Xcode 26 recommended)
Clerk Feature Support on Expo 54
@clerk/expo v3.1.x provides full support for all three authentication approaches on Expo SDK 54:
- Approach 1 (JavaScript custom flows): Fully supported in both Expo Go and development builds
- Approach 2 (JavaScript + native hooks): Fully supported in development builds
- Approach 3 (Native components): Supported in beta in development builds
Both the Legacy Architecture and the New Architecture are compatible with @clerk/expo. The SDK v3.1.5 release added the -Xskip-metadata-version-check Kotlin compiler flag for SDK 54 and SDK 55 compatibility, and fixed an Android New Architecture codegen error related to the NativeClerkModule.
Token caching with expo-secure-store works as expected on SDK 54. Passkeys are supported via @clerk/expo-passkeys, which includes SDK 54 in its peer dependency range (expo: >=53 <57).
There are no known Clerk-specific caveats unique to SDK 54.
Expo SDK 55 Compatibility
Expo 55 at a Glance
Expo SDK 55 was released on February 25, 2026. It ships React Native 0.83 and React 19.2, which introduces the Activity component and the useEffectEvent hook.
The most significant change in SDK 55 is that the New Architecture is mandatory. The newArchEnabled configuration option has been removed and the Legacy Architecture is no longer available. Approximately 83% of SDK 54 projects on EAS Build were already using the New Architecture before SDK 55 shipped.
Other notable changes in SDK 55:
- Hermes v1 available as an opt-in JavaScript engine. Enable it by setting
useHermesV1: trueandbuildReactNativeFromSource: truein theexpo-build-propertiesplugin, and overriding thehermes-compilerversion inpackage.json. Hermes v1 offers meaningful performance improvements and better support for modern JavaScript features. Caveat: it requires building React Native from source, which significantly increases native build times. It is not yet recommended for Android in monorepo projects. - Bytecode diffing for OTA updates — approximately 75% smaller update downloads
- Minimum Xcode 26 required (see Xcode versioning note in the Version Support Matrix)
- Native Tabs API and Apple Zoom transitions for enhanced navigation
- All Expo SDK packages now use matching major version numbers (e.g.,
expo-camera@^55.0.0)
Clerk Feature Support on Expo 55
@clerk/expo v3.1.0 added explicit Expo SDK 55 support by updating its peer dependency to expo: >=53 <56. All three authentication approaches are confirmed working:
- Approach 1 (JavaScript custom flows): Fully supported
- Approach 2 (JavaScript + native hooks): Fully supported
- Approach 3 (Native components): Supported in beta
The New Architecture is fully compatible with @clerk/expo. TurboModules and the Fabric renderer work without issues.
Passkeys are supported on SDK 55. @clerk/expo-passkeys v1.1.0 expanded its peer dependency to expo: >=53 <57, which formally includes Expo SDK 55. Upgrade to the latest @clerk/expo-passkeys release; versions up to v1.0.13 capped support at expo: >=53 <55 and excluded SDK 55. See the Passkeys section for configuration details.
Several open GitHub issues affect SDK 55 users. See the Known Issues and Limitations section for current status.
New Architecture Impact on Clerk Authentication
The mandatory New Architecture in SDK 55 requires no action from Clerk users. The @clerk/expo package uses expo-modules-core for native module integration, which supports the New Architecture by default.
Clerk's native components use JSI-based TurboModules for JavaScript-to-native communication. The Fabric renderer is fully compatible — no rendering issues have been reported.
React Native 0.83 introduced the option to compile out Legacy Architecture code entirely by setting RCT_REMOVE_LEGACY_ARCH=1. This produces approximately 20% faster iOS builds and approximately 6% smaller app size. This optimization is compatible with Clerk.
TurboModules also improve performance for Clerk operations by lazy-loading native modules on demand rather than eagerly loading them at startup, which reduces cold-start memory usage.
Expo Go vs. Development Builds
What Works in Expo Go
Expo Go supports Approach 1 only — JavaScript custom flows. The following features work in Expo Go:
- Email/password sign-in and sign-up
- Phone verification (OTP)
- Magic links
- Session management:
useAuth(),useUser(),useSession() - Conditional rendering:
<Show when="signed-in">,<Show when="signed-out"> - Loading states:
<ClerkLoaded>,<ClerkLoading> - Token caching with
expo-secure-store - Organizations, RBAC, and user management hooks
The following features do not work in Expo Go: social OAuth (useSSO()), native Google Sign-In, native Apple Sign-In, native components, passkeys, and biometric sign-in. Expo Go cannot register custom URL schemes (required for OAuth redirects) and cannot load custom native modules.
What Requires a Development Build
A development build is required for:
- Social OAuth via
useSSO()— custom URL scheme redirect required - Native Google Sign-In via
useSignInWithGoogle - Native Apple Sign-In via
useSignInWithApple - Native components (
<AuthView />,<UserButton />,<UserProfileView />) - Passkeys via
@clerk/expo-passkeys - Biometric sign-in via
useLocalCredentials - Custom URL scheme registration for deep linking
Choosing the Right Environment
Start with Expo Go for initial setup and email/password flows. Switch to a development build when adding social or native authentication.
Two ways to create a development build:
- Local build (
npx expo run:ios/npx expo run:android): Compiles using locally installed Xcode (iOS, macOS only) or Android Studio. Best for rapid iteration — rebuilds only changed native code on subsequent runs. No EAS account required. Note: a paid Apple Developer Program membership ($99/year) is effectively required for Apple Sign-In entitlement configuration, Associated Domains (needed for passkeys), and App Store distribution. - EAS Build (
eas build --profile development): Builds on remote EAS servers with no local native tooling required. Can build iOS from Windows or Linux. Handles credential management (certificates, provisioning profiles) automatically. Best for team builds, CI/CD, and distribution.
A new development build is required whenever native configuration changes (adding a URL scheme, passkey support, native sign-in, or plugins). JavaScript-only changes load via the dev server without rebuilding.
Authentication Methods in Detail
Native Google Sign-In
Native Google Sign-In provides a platform-native credential picker on both iOS and Android, with no browser redirect:
- iOS: Uses ASAuthorization — the system credential picker that appears natively
- Android: Uses Credential Manager — a system bottom sheet with one-tap support
Prerequisites:
- A development build (does not work in Expo Go)
- Clerk Dashboard: Register your native app — Team ID + Bundle ID for iOS, package name + SHA-256 fingerprint for Android
- Google Cloud Console: Create OAuth 2.0 credentials — an iOS Client ID, an Android Client ID, and a Web Application Client ID (the web client is required even for native apps)
- Environment variables:
EXPO_PUBLIC_CLERK_GOOGLE_WEB_CLIENT_ID,EXPO_PUBLIC_CLERK_GOOGLE_IOS_CLIENT_ID(iOS),EXPO_PUBLIC_CLERK_GOOGLE_IOS_URL_SCHEME(iOS) - Add the
@clerk/expoplugin toapp.json(see Plugin Configuration) - Install peer dependency:
expo-crypto
import { useSignInWithGoogle } from '@clerk/expo/google'
import { Pressable, Text } from 'react-native'
export function GoogleSignInButton() {
const { startGoogleAuthenticationFlow } = useSignInWithGoogle()
const onPress = async () => {
try {
const { createdSessionId, setActive } = await startGoogleAuthenticationFlow()
if (createdSessionId) {
await setActive({ session: createdSessionId })
}
} catch (err) {
console.error('Google sign-in error:', err)
}
}
return (
<Pressable onPress={onPress}>
<Text>Sign in with Google</Text>
</Pressable>
)
}For detailed setup instructions including Google Cloud Console configuration, see Configure native Google Sign-In for Expo.
Native Apple Sign-In
Native Apple Sign-In uses Apple's authentication UI on iOS. It is iOS only — the hook returns null on non-iOS platforms. If your app offers social sign-in alongside another provider (e.g., Google), Apple may require "Sign in with Apple" for App Store approval.
Native Apple Sign-In supports Apple's Hide My Email privacy feature automatically.
Prerequisites:
- A development build
- Install peer dependencies:
expo-apple-authentication,expo-crypto - Clerk Dashboard: Register App ID Prefix (Team ID) + Bundle ID
When using native components, Apple Sign-In is automatically available in <AuthView /> when Apple is enabled in the Clerk Dashboard. For a custom UI, use the useSignInWithApple hook:
import { useSignInWithApple } from '@clerk/expo/apple'
import { Platform, Pressable, Text } from 'react-native'
export function AppleSignInButton() {
const signInWithApple = useSignInWithApple()
if (!signInWithApple || Platform.OS !== 'ios') return null
const onPress = async () => {
try {
const { createdSessionId, setActive } = await signInWithApple.startAppleAuthenticationFlow()
if (createdSessionId) {
await setActive({ session: createdSessionId })
}
} catch (err) {
console.error('Apple sign-in error:', err)
}
}
return (
<Pressable onPress={onPress}>
<Text>Sign in with Apple</Text>
</Pressable>
)
}For detailed configuration, see Configure native Apple Sign-In for Expo.
Browser-Based SSO
useSSO() opens the system browser for OAuth and enterprise SSO flows. It replaces the deprecated useOAuth() hook — all new code should use useSSO().
The browser experience uses ASWebAuthenticationSession on iOS and Chrome Custom Tabs on Android. useSSO() supports 31+ social providers (Google, GitHub, Discord, LinkedIn, and more) as well as enterprise SSO protocols (SAML, OIDC, EASIE).
useSSO() requires a development build. Expo Go cannot register custom URL schemes, which are required for the post-authentication redirect back to the app.
Key parameters:
strategy:'oauth_<provider>'for social login, or'enterprise_sso'for enterprise SSOidentifier: Required for enterprise SSO to identify the connectionredirectUrl: Generated viaAuthSession.makeRedirectUri()
import { useSSO } from '@clerk/expo'
import * as AuthSession from 'expo-auth-session'
import * as WebBrowser from 'expo-web-browser'
import { Pressable, Text, Platform } from 'react-native'
import { useEffect } from 'react'
export function SSOSignInButton() {
const { startSSOFlow } = useSSO()
useEffect(() => {
// Warm up the browser on Android for faster opening
if (Platform.OS === 'android') {
void WebBrowser.warmUpAsync()
return () => {
void WebBrowser.coolDownAsync()
}
}
}, [])
const onPress = async () => {
try {
const { createdSessionId, setActive } = await startSSOFlow({
strategy: 'oauth_google',
redirectUrl: AuthSession.makeRedirectUri(),
})
if (createdSessionId) {
await setActive({ session: createdSessionId })
}
} catch (err) {
console.error('SSO error:', err)
}
}
return (
<Pressable onPress={onPress}>
<Text>Sign in with Google (Browser)</Text>
</Pressable>
)
}Browser-based SSO offers broader provider support than native sign-in but trades UX polish for compatibility — users see a browser redirect rather than a system credential picker. For Google and Apple, native sign-in hooks provide a more seamless experience.
Passkeys
Clerk supports native passkeys in Expo via the @clerk/expo-passkeys package. Passkeys use WebAuthn to provide phishing-resistant, passwordless authentication bound to the device and domain.
- Create a passkey:
user.createPasskey() - Sign in with a passkey:
signIn.authenticateWithPasskey()
Platform requirements:
- iOS 16+ with Associated Domains entitlement
- Android 9+ with a physical device (emulators are not supported)
- Maximum 10 passkeys per account, domain-locked
iOS configuration requires adding associated domains to app.json:
applinks:<FAPI_URL>andwebcredentials:<FAPI_URL>- Set
ios.deploymentTarget: "16.0"via theexpo-build-propertiesplugin - Register App ID Prefix + Bundle ID in the Clerk Dashboard under Native Applications
Android configuration requires intent filters with autoVerify: true in app.json, pointing to your Clerk FAPI domain. Clerk hosts the assetlinks.json file on the FAPI domain — configure it via the Clerk Dashboard (Native Applications > Android), not self-hosted. Register the package name and SHA-256 fingerprints for each build environment.
// In your root layout, configure ClerkProvider with passkeys
import { ClerkProvider } from '@clerk/expo'
import { passkeys } from '@clerk/expo-passkeys'
import { tokenCache } from '@clerk/expo/token-cache'
export default function RootLayout() {
return (
<ClerkProvider
publishableKey={process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY!}
tokenCache={tokenCache}
__experimental_passkeys={passkeys}
>
{/* Your app */}
</ClerkProvider>
)
}In a sign-in component, authenticate with a passkey:
import { useSignIn } from '@clerk/expo'
import { Pressable, Text } from 'react-native'
export function PasskeySignIn() {
const { signIn, setActive } = useSignIn()
const onPress = async () => {
try {
const result = await signIn!.authenticateWithPasskey()
await setActive({ session: result.createdSessionId })
} catch (err) {
console.error('Passkey sign-in error:', err)
}
}
return (
<Pressable onPress={onPress}>
<Text>Sign in with Passkey</Text>
</Pressable>
)
}For detailed configuration including iOS Associated Domains and Android intent filters, see Configure passkeys for Expo.
Biometric Sign-In
The useLocalCredentials hook from @clerk/expo/local-credentials enables returning users to sign in using Face ID, Touch ID, or fingerprint authentication. It works by storing the user's password credentials securely on the device after their initial sign-in, then retrieving and auto-submitting them after biometric verification.
Requirements:
@clerk/expov2.2.0 or laterexpo-local-authenticationv13.5.0 or later- Password-based sign-in strategy enabled (does not work with OAuth-only accounts)
- Device must have enrolled biometrics and a passcode
- Development build required
The hook provides these key properties and methods:
hasCredentials: Whether saved credentials exist on this deviceuserOwnsCredentials: Whether the saved credentials belong to the current userbiometricType:'face-recognition','fingerprint', ornullsetCredentials(): Save the current user's password after initial sign-inclearCredentials(): Remove saved credentialsauthenticate(): Trigger biometric prompt and sign in
Credentials are automatically deleted if the device passcode is removed.
import { useLocalCredentials } from '@clerk/expo/local-credentials'
import { useSignIn } from '@clerk/expo'
import { Pressable, Text } from 'react-native'
export function BiometricSignIn() {
const { hasCredentials, biometricType, authenticate, setCredentials } = useLocalCredentials()
const { signIn, setActive } = useSignIn()
if (hasCredentials && biometricType) {
return (
<Pressable
onPress={async () => {
try {
const { createdSessionId } = await authenticate()
if (createdSessionId) {
await setActive({ session: createdSessionId })
}
} catch (err) {
console.error('Biometric auth failed:', err)
}
}}
>
<Text>Sign in with {biometricType === 'face-recognition' ? 'Face ID' : 'Fingerprint'}</Text>
</Pressable>
)
}
// After a successful password sign-in, offer to save credentials
// by calling setCredentials() to store for future biometric sign-in
return null
}For complete setup instructions, see Configure biometric sign-in for Expo.
Next Steps
This concludes Part 1 of the compatibility reference, covering version requirements, environments, and core authentication hooks. In Part 2, we explore the new beta Native Components, token caching, user and organization management, setup configuration, and production deployment considerations.
FAQ
In this series
- Clerk Compatibility in Expo 54 and 55 (you are here)
- Clerk Compatibility in Expo 54 and 55 - Part 2