Native app feature coverage | Expo Supabase SaaS Kit

Which Makerkit features the Expo app covers, which deliberately stay on web, and which are planned. Includes the flag, platform and store constraint for every feature.

What the Expo app in apps/native covers, feature by feature, against the web kit it ships alongside.

As of kit 4.0.1, Expo SDK 57 (React Native 0.86). Statuses describe the code in this repository, not a roadmap commitment.

Legend

StatusMeaning
ParityWorks natively and behaves like web.
AdaptedWorks natively, deliberately different from web. The difference is always stated.
PlannedNot built. Intended.
Web-onlyExists in the product, deliberately stays on web. Native users are sent to the web app.
DeclinedEvaluated and rejected. The reason is stated, so the decision isn't re-litigated.

A † on a Planned row means it also needs credentials or hosting you must provide: an Apple Services ID, a real HTTPS domain, .well-known files. Nobody can finish or test those locally.

Unless a row says otherwise, a feature behaves the same on iOS and Android.


Authentication and session

FeatureStatusFlagNotes
Email + password sign-inParityEXPO_PUBLIC_AUTH_PASSWORD (on)Shares web's PasswordSignInSchema.
Sign-outParityClears the query cache and the stored session.
Session persistenceAdaptedJWT in Keychain / Keystore via expo-secure-store, not an httpOnly cookie. Restored on cold start.
MFA challenge (TOTP)ParityFactor picker, auto-submit on the sixth digit.
Sign-upAdaptedEXPO_PUBLIC_AUTH_PASSWORDConfirmed with a 6-digit emailed code, not a confirmation link.
Password resetAdaptedThree steps: request, enter the emailed code, set the new password. No link round-trip.
Google OAuthParityEXPO_PUBLIC_AUTH_OAUTH_PROVIDERSPKCE in the system browser, then exchangeCodeForSession. Reuses your existing Supabase Web OAuth client.
Other OAuth providersParityEXPO_PUBLIC_AUTH_OAUTH_PROVIDERSProvider-generic: enabling one is configuration plus a logo asset, not code.
Sign in with AppleAdaptedEXPO_PUBLIC_AUTH_OAUTH_PROVIDERS (off)iOS only, since Android filters it out. A native signInWithIdToken sub-flow, not the browser flow. Off by default, because the entitlement makes even simulator builds require a paid Apple signing team. Required by App Store review once you offer Google — see store requirements.
Accept a team invitationAdaptedMatched to your verified email inside the app, not by opening an emailed link.
Passwordless / magic linkPlannedEXPO_PUBLIC_AUTH_MAGIC_LINK, EXPO_PUBLIC_AUTH_OTPThe flags exist and are read; no screens consume them yet.
Passkeys: list, rename, deletePlannedWeb's passkey code is browser-only, but supabase-js exposes a headless auth.passkey.* API that works in React Native. Management needs no new infrastructure.
Passkeys: register and sign inPlanned †Needs relying-party domain association: a real HTTPS domain, Apple Team ID, Android release SHA-256. A localhost RP cannot be bound, so this is not locally testable.
Captcha (Turnstile)Web-onlyNative carries no Turnstile token. Bot protection is rate-limiting instead. Never enable the global GoTrue captcha toggle. It gates sign-in, OTP and reset for every client and breaks native auth outright.
Recovery codesWeb-onlyNot surfaced on either platform today.

Personal account

FeatureStatusFlagNotes
Display nameParity
Avatar uploadParityUploads to the account_image bucket.
Change passwordParity
MFA enroll (TOTP)AdaptedNo QR scanner. Opens an otpauth:// link into your authenticator, with a copyable secret as fallback.
MFA factor list / unenrollParity
Delete accountParityEXPO_PUBLIC_ENABLE_PERSONAL_ACCOUNT_DELETION (off)OTP-confirmed. Both stores require in-app deletion, so this cannot be a link out to web.
Change emailPlannedRead-only today, with a "manage on web" notice. Needs a double confirmation, old address and new.
Identity linkingPlannedEXPO_PUBLIC_AUTH_IDENTITY_LINKING (off)Unblocked now that OAuth ships; it reuses the same flow.
Language preferencePlannedThe row exists but is disabled: the app ships English only.

Team accounts

FeatureStatusFlagNotes
Create a teamParityEXPO_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION (on)
Rename, change slugParitySlug regenerates from the name. Primary-owner-only, enforced by RLS.
Team logoParity
Leave a teamParityTyped confirmation. The primary owner is refused.
Delete a teamPlannedEXPO_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETION (off)Shows a "manage on web" notice today. The OTP-confirm pattern it needs already ships with personal deletion, so this is a port rather than new infrastructure.
Transfer ownershipPlannedVisible to the primary owner as a disabled row today, mirroring web's visibility. Reuses the same OTP-confirm pattern.

Members, invitations and roles

FeatureStatusFlagNotes
Members listParity
Invite membersParity
Pending invitations listParity
Change an invitation's roleParity
Revoke an invitationParity
Renew an invitationParity
Change a member's roleParity
Remove a memberParityPer-seat billing decrements server-side, same service as web.
Roles and permission gatingParityThe role list is hierarchy-filtered server-side, so the app never sees roles it may not assign.

Billing

FeatureStatusFlagNotes
Subscription statusAdaptedRead-only badge in team settings. No personal-account view.
Plan selection, checkout, customer portalWeb-onlyA commercial decision rather than a technical gap. See the note below.
Per-seat and metered billingWeb-onlySeat counts still update correctly from native member changes, because the shared service owns them.
Billing webhooksWeb-onlyServer infrastructure; no client involvement.

Notifications

FeatureStatusFlagNotes
In-app list, bell, unread badgePlannedNo native surface. Portable: it reads Supabase directly, so no new infrastructure. Web's notifications strings are already in the inherited catalogue.
Mark as read / dismissPlanned
Realtime deliveryPlannedsupabase.channel() works from native as-is.
Push notificationsPlanned †A separate track from the in-app bell: APNs and FCM credentials, per-device token storage, an OS permission prompt, and server-side sending. Delivered by the OS even when the app is closed.

App shell and cross-cutting

FeatureStatusFlagNotes
Workspace switcherParityPersonal plus teams, with create.
Workspace contextParitySelection persisted in secure storage.
NavigationAdaptedNative tab bars (Home, Settings, plus Members for a team) instead of web's sidebar.
User menuParity
Theme: light / dark / systemParityWeb's enableThemeToggle has no native counterpart; the toggle always ships.
Membership and route guardsParityEnforced in native layouts, same rules as web's.
i18n infrastructureAdaptedInherits web's catalogue and keeps only a local delta, so a string fixed on web propagates. Ships English only.
Home dashboard contentPlannedThin placeholders on both personal and team contexts, as on web.
App-level language switcherPlannedOnly worth wiring once you ship a second locale.
Version updaterWeb-onlyNative has no over-the-air update channel configured (expo-updates is not installed); app updates go through the stores.

Admin and super-admin

FeatureStatusFlagNotes
Admin dashboardWeb-only
Browse and inspect accountsWeb-only
Ban, reactivate, delete a userWeb-only
Delete an accountWeb-only
Impersonate a userWeb-only
Reset a user's passwordWeb-only

Administration is an operator tool. is_super_admin() returns false unless the session is AAL2, so super-admin plus MFA is enforced in the database rather than only in the app. Shipping the surface in a store-distributed binary would widen the attack surface for no user benefit, so the whole domain stays on web.

Marketing and content

FeatureStatusNotes
Landing page, pricing, FAQ, contactWeb-onlyAcquisition surfaces, aimed at visitors who have not installed the app.
Blog, changelogWeb-only
Legal pages (terms, privacy)AdaptedOnly the sign-up terms checkbox, which links out to your deployed web app, so EXPO_PUBLIC_SITE_URL must point at a real host in a release build.
Documentation siteWeb-only
CMS integration (Keystatic, WordPress)Web-onlyContent rendering is a web concern; native imports no CMS client.

The app's catalogue never inherits the marketing message namespace, so those strings stay out of the bundle.

Native-only features

Capabilities with no web counterpart, most of them required by the app stores.

FeatureStatusNotes
Secure session storageParityKeychain / Keystore via expo-secure-store.
Device-locale detectionParityPicks the initial language from the OS.
Device info diagnosticsPlannedfeatures/device-info/device-info-card.tsx ships as a component, but nothing renders it — there is no route and no entry point. Mount it on a screen of your own to use it.
In-app account deletionParityWeb offers it too, but on native it is store-mandated rather than optional.
Universal LinksPlanned †Not implemented: no flag, no associatedDomains, no intentFilters. Needs hosted .well-known files, an Apple Team ID and an Android release SHA-256. Kept off the auth critical path, since typed codes made it unnecessary.
Biometric sign-inPlanned †Needs the same domain association as passkey registration.

Integrations

IntegrationStatusNotes
Supabase AuthParityCalled directly with the JS SDK.
Supabase DatabaseAdaptedReached over the kit's versioned /api/v1/* endpoints rather than directly, so authorization and business rules stay in one place.
Supabase StorageParityDirect uploads for avatars and logos.
Supabase RealtimePlannedWorks from native; nothing consumes it yet.
Stripe / Lemon SqueezyWeb-onlySee Billing.
Resend / NodemailerWeb-onlyServer-side senders. Native triggers emails through the API, never sends them.
Sentry / monitoringPlannedWeb's provider is wired for a Next.js runtime; native error reporting is not configured.
Analytics providersPlannedNo native analytics client.
Cloudflare TurnstileDeclinedNo native SDK exists. Wrapping the widget in a WebView was rejected as a poor trade for a sign-up form.
Keystatic / WordPress CMSWeb-only

Platform and store requirements

These gate shipping rather than adding features. docs/native/config-requirements.mdoc has the configuration detail.

RequirementTriggerStatus
Sign in with Apple (App Store 4.8)Offering Google or any social login on iOSImplemented, off by default. Turn it on before an iOS submission.
Apple token revocation (App Store 5.1.1(v))Sign in with Apple and account deletion both presentPlanned †. A hard blocker for iOS submission. Apple requires revoking the token on deletion, and Supabase does not do it for you: it needs an Apple Services ID and .p8 key, a server-side authorization-code exchange at sign-in to capture a refresh token, and a revoke call during deletion.
In-app account deletion (App Store 5.1.1(v), Play)Any in-app account creationImplemented. Must stay reachable in-app; a link to web is not accepted.
Privacy labels / Play Data SafetyOAuth collecting email or nameDeclare at submission. Revisit when adding a provider.

Rejected approaches

Recorded so they aren't proposed again.

ApproachWhy not
A WebView wrapper around the web appThe point of the native app is real native screens against a shared API. A WebView inherits web's cookie and navigation model and fails the "minimum functionality" bar at review. May still suit an isolated advanced surface later.
@expo/ui native componentsLooks more native, but most components would need separate iOS and Android implementations, and its styling model diverges from the rest of the repo. Staying on cross-platform primitives keeps the component API matched to web's.
Origin-aware emailing (different email for app vs web)There is no reliable platform signal at send time, and the requesting device is often not the opening device.
A QR code for MFA enrollmentNeeds a camera permission and a scanner dependency to solve a problem an otpauth:// link already solves, on the device that holds the authenticator.
Turnstile in a WebViewSee Integrations.

Configuration parity

Every public setting web exposes, and whether native honours it. Where a setting means the same thing on both, native reuses web's name with an EXPO_PUBLIC_ prefix, so an existing .env mostly transfers by search-and-replace.

Statuses read the same as the feature tables: Parity mirrored, Adapted honoured differently, Planned no native setting yet, Web-only / Declined never will be. Build-tooling variables (NEXT_PUBLIC_CI) are omitted.

Feature flags

WebNativeStatusNotes
ENABLE_TEAM_ACCOUNTSEXPO_PUBLIC_ENABLE_TEAM_ACCOUNTS (on)Parity
ENABLE_TEAM_ACCOUNTS_ONLYEXPO_PUBLIC_ENABLE_TEAM_ACCOUNTS_ONLY (off)Parity
ENABLE_TEAM_ACCOUNTS_CREATIONEXPO_PUBLIC_ENABLE_TEAM_ACCOUNTS_CREATION (on)Parity
ENABLE_TEAM_ACCOUNTS_DELETIONEXPO_PUBLIC_ENABLE_TEAM_ACCOUNTS_DELETION (off)ParityGates the "manage on web" notice, since the native flow is still Planned. The committed .env.development sets it to true, so it is on in local dev.
ENABLE_PERSONAL_ACCOUNT_DELETIONEXPO_PUBLIC_ENABLE_PERSONAL_ACCOUNT_DELETION (off)ParityThe committed .env.development sets it to true, so it is on in local dev.
LANGUAGE_PRIORITYAdaptedNative always resolves from the device locale, which is web's user setting. Web defaults to application. Not configurable natively.
ENABLE_THEME_TOGGLEPlannedThe toggle always ships; hiding it is a small addition nobody has needed yet.
ENABLE_NOTIFICATIONSPlannedArrives with the notifications surface.
REALTIME_NOTIFICATIONSPlannedSame.
ENABLE_PERSONAL_ACCOUNT_BILLINGWeb-only
ENABLE_TEAM_ACCOUNTS_BILLINGWeb-only
ENABLE_VERSION_UPDATER, VERSION_UPDATER_REFETCH_INTERVAL_SECONDSDeclinedStore-distributed builds, no OTA channel.

Authentication

WebNativeStatusNotes
AUTH_PASSWORDEXPO_PUBLIC_AUTH_PASSWORD (on)Parity
DISPLAY_TERMS_AND_CONDITIONS_CHECKBOXEXPO_PUBLIC_DISPLAY_TERMS_AND_CONDITIONS_CHECKBOX (off)ParityTurning it on also requires EXPO_PUBLIC_SITE_URL to point at your deployed web app, since the two links open there.
PASSWORD_REQUIRE_SPECIAL_CHARS, _NUMBERS, _UPPERCASEEXPO_PUBLIC_PASSWORD_REQUIRE_* (all off)ParityMirror these or native accepts what web rejects. Both platforms validate client-side only, and the settings change-password screen honours neither.
AUTH_MAGIC_LINKEXPO_PUBLIC_AUTH_MAGIC_LINK (off)PlannedThe flag is read; no screen consumes it.
AUTH_OTPEXPO_PUBLIC_AUTH_OTP (off)PlannedSame.
AUTH_IDENTITY_LINKINGEXPO_PUBLIC_AUTH_IDENTITY_LINKING (off)PlannedSame.
AUTH_PASSKEYPlanned
CAPTCHA_SITE_KEY, CAPTCHA_WIDGET_SIZEDeclinedNo native Turnstile SDK. See Authentication.
— (web hardcodes oAuth: ['google'])EXPO_PUBLIC_AUTH_OAUTH_PROVIDERSAdaptedNative made the provider list configurable; web still edits the array in auth.config.ts.

Branding and appearance

WebNativeStatusNotes
PRODUCT_NAMEEXPO_PUBLIC_PRODUCT_NAMEParity
SITE_URLEXPO_PUBLIC_SITE_URLAdaptedOn web it is the app's own origin; on native it is where outbound links go. A loopback default is dead in a release build.
DEFAULT_THEME_MODEPlannedNative defaults to following the OS and persists the user's choice; the default is not yet configurable.
THEME_COLOR, THEME_COLOR_DARKDeclinedWeb writes these into the document head for browser chrome. Native colours its navigation chrome from the theme tokens through React Navigation, and app.json sets the static launch background. No env override.
DEFAULT_LOCALEAdaptedResolved from the device locale. The app ships English only.
SITE_TITLE, SITE_DESCRIPTIONDeclinedDocument-head metadata for search engines and social previews. An app has no document head; the store listing plays that role.
WebNativeStatusNotes
USER_NAVIGATION_STYLE, TEAM_NAVIGATION_STYLEDeclinedWeb picks sidebar or header. Native uses platform tab bars, so there is no equivalent setting to expose.
HOME_SIDEBAR_COLLAPSED, TEAM_SIDEBAR_COLLAPSED, SIDEBAR_COLLAPSIBLE_STYLEDeclinedNo sidebar exists to collapse.

Web's navigation items come from personal-account-navigation.config.tsx and team-account-navigation.config.tsx. Native declares its tabs in the route layouts instead, so adding a screen to one platform does not add it to the other.

Billing

WebNativeStatus
BILLING_PROVIDERWeb-only

Native-only settings

No web counterpart, because web has no equivalent need.

SettingPurpose
EXPO_PUBLIC_API_BASE_URLWhich web deployment serves /api/v1/*. The one knob for pointing the app at a different backend.
EXPO_PUBLIC_SUPABASE_URL, EXPO_PUBLIC_SUPABASE_PUBLIC_KEYDirect SDK access for auth, MFA and storage.

The mirrored ones are enableTeamAccounts, enableTeamsOnly, enableTeamCreation, enableTeamDeletion and enableAccountDeletion, each with an EXPO_PUBLIC_* twin. Native also adds auth and password-policy flags of its own. Both sets, and what a change to one forces elsewhere, are in docs/native/config-requirements.mdoc.