Removing features and integrations
Take the example features and optional vendors your app will not use out of the codebase with two scripts, before you configure anything.
Prerequisites
- A clean git tree, so the diff is reviewable and reversible
- Decisions on what to keep, recorded in the product brief
Remove a feature
yarn remove:feature create --dry-run
yarn remove:feature createChat, Create and Scan are independent examples under src/features/. Pass one or
several of chat, create and scan. --dry-run lists what would change without
touching anything.
The script removes the feature’s registration in src/features/index.ts, its directory
under src/features/, its route files, its edge function, its SQL block in the initial
migration and its Maestro flow. It refuses when the feature is already gone, and stops at
a file you have already reshaped by hand, naming it, so you finish that step yourself.
What stays: the shared services, the chat-media bucket and the quota tables. Chat and
Scan draw on the same monthly allowance and Create needs Pro, so removing a history
table does not change usage counting. Translation keys and analytics event declarations
can keep unused entries. .maestro/smoke.yaml still asserts every tab; trim it to the
tabs you keep.
Afterwards, apply the migration to your Supabase project, regenerate the types with
PROJECT_REF=<ref> yarn supabase:db-types, and run yarn ci. Deleting a function’s
source does not undeploy it; remove it from your Supabase project separately if it was
already deployed.
Remove an integration
yarn remove:integration sentry --dry-run
yarn remove:integration sentryPass one of sentry, onesignal or posthog. The script removes the vendor adapter,
its config-plugin entry in app.config.js, its .env.example block, its lint fence and
its setup reference. The port and its no-op stay, so every call site keeps compiling.
| Integration | What changes | What remains for you |
|---|---|---|
sentry | src/services/crash-reporting/sentry.adapter.ts is deleted and the no-op wired into src/services/crash-reporting/index.ts. metro.config.js falls back to expo/metro-config. The Jest mock, the expo.install.exclude entry and the plugin block go too | logError keeps working and logs to the console in development |
onesignal | src/services/push.ts becomes a no-op with the same exports. The onesignal-expo-plugin entry and the ONESIGNAL_MODE logic leave app.config.js | The onboarding notifications screen asks for a permission nothing consumes; delete or repurpose it |
posthog | The PostHog adapter and client are deleted, the no-op wired into src/services/analytics/analytics.ts, and AnalyticsProvider becomes a passthrough | The typed event registry stays, so trackEvent calls still compile |
Neither script runs yarn remove. It prints the exact command; run it, then yarn ci.
Not removable by script
yarn remove:integration exits non-zero with the reason for these three:
| Integration | Why |
|---|---|
| RevenueCat | react-native-purchases backs RevenueCatProvider, the Pro gate on Create, the paywall screens and the edge functions’ REVENUECAT_SECRET_KEY check, and Superwall bridges through it |
| Superwall | expo-superwall is wired into PaywallProvider, purchaseController and SubscriptionSync. Leave EXPO_PUBLIC_SUPERWALL_API_KEY_APPLE and EXPO_PUBLIC_SUPERWALL_API_KEY_GOOGLE unset and RevenueCat’s own paywall is used |
| Google sign-in | Three auth screens render its button, config.js carries the OAuth client IDs, and app.config.js carries the plugin and its iOS pod settings |
Each of them stays off while its keys are unset. What the script cannot do is remove
the package from package.json.
Apple sign-in has no script either. Turning it off only makes sense for an app without
Google sign-in, because Apple requires it alongside Google sign-in on iOS. Remove the
Apple AuthButton from the sign-in and sign-up screens by hand and drop
useSignInWithApple.
Never remove on a guess. The notifications primer is part of onboarding and comes out with push, so “I don’t think I need push” is a question to settle first.
Verify
yarn ciTwo CI checks prove that removal keeps working as the codebase changes:
| Check | What it does |
|---|---|
yarn check:feature-variants | Copies the source to temporary directories, runs yarn remove:feature there and checks Chat only, Create only, Scan only and the empty shell: docs, route types, typecheck, Jest and the remaining edge functions |
yarn check:integration-variants | For each of sentry, onesignal and posthog: makes the vendor’s packages unresolvable the way yarn remove leaves them, loads metro.config.js and app.config.js against that, runs the removal script, then typechecks, lints, tests and re-checks the docs and skill mirrors |
Neither modifies your checkout or connects to a database. Run yarn check:db
separately against the schema you keep.