Build production-ready Expo mobile apps with TypeScript, Supabase backend, AI integration, and paywalls. Optimized for AI-assisted development with single-language stack and best practices.
An AI-first Expo mobile app starter template built with TypeScript, optimized for rapid development with AI assistance. Ship production-ready mobile apps with authentication, database, AI integration, and paywalls in days, not weeks.
This skill guides you in building and working with a modern mobile app stack that uses:
The stack is designed for minimal friction, single-language development, and AI-friendly patterns.
```
apps/mobile/
├── app/ # expo-router routes
│ ├── _layout.tsx # Root layout with theme provider
│ ├── (tabs)/ # Bottom tab navigation
│ ├── (auth)/ # Auth flow screens
│ └── paywall.tsx # Superwall integration
├── lib/ # Core integrations
│ ├── supabase.ts # Supabase client setup
│ ├── queryClient.ts # TanStack Query config
│ └── superwall.ts # Superwall setup
├── features/ # Feature modules
├── components/ui/ # Paper component wrappers
├── stores/ # Zustand stores (minimal)
├── env.ts # Zod-validated config
└── types/ # TypeScript types
supabase/
├── functions/
│ └── ai/index.ts # AI endpoint with SSE streaming
├── migrations/ # SQL migrations
└── types/database.ts # Generated DB types
```
1. **Initialize the Expo project**
```bash
pnpm create expo-app --template expo-template-blank-typescript
pnpm install
```
2. **Install core dependencies**
```bash
pnpm add expo-router @supabase/supabase-js @tanstack/react-query react-native-paper react-hook-form zod @hookform/resolvers react-native-mmkv zustand
pnpm add -D @types/react @types/react-native
```
3. **Set up Supabase project**
- Create project at supabase.com
- Note project URL and anon key
- Initialize local Supabase CLI: `supabase init`
4. **Create environment configuration**
- Create `env.ts` with Zod validation:
```typescript
import { z } from 'zod';
const envSchema = z.object({
EXPO_PUBLIC_SUPABASE_URL: z.string().url(),
EXPO_PUBLIC_SUPABASE_ANON_KEY: z.string(),
EXPO_PUBLIC_POSTHOG_KEY: z.string().optional(),
});
export const env = envSchema.parse({
EXPO_PUBLIC_SUPABASE_URL: process.env.EXPO_PUBLIC_SUPABASE_URL,
EXPO_PUBLIC_SUPABASE_ANON_KEY: process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY,
EXPO_PUBLIC_POSTHOG_KEY: process.env.EXPO_PUBLIC_POSTHOG_KEY,
});
```
5. **Configure TypeScript path aliases**
- Update `tsconfig.json`:
```json
{
"compilerOptions": {
"paths": {
"@/*": ["./*"]
}
}
}
```
6. **Set up Supabase client**
- Create `lib/supabase.ts`:
```typescript
import { createClient } from '@supabase/supabase-js';
import { env } from '@/env';
import type { Database } from '@/supabase/types/database';
export const supabase = createClient<Database>(
env.EXPO_PUBLIC_SUPABASE_URL,
env.EXPO_PUBLIC_SUPABASE_ANON_KEY
);
```
7. **Generate TypeScript types from Supabase schema**
```bash
supabase gen types typescript --project-id <project-id> > supabase/types/database.ts
```
1. **Create core database tables**
- Create migration file in `supabase/migrations/`
- Define tables: `profiles`, `questionnaires`, `answers`, `habits`, `habit_logs`, `messages`
- Enable RLS on all tables:
```sql
alter table profiles enable row level security;
alter table answers enable row level security;
alter table habits enable row level security;
alter table habit_logs enable row level security;
alter table messages enable row level security;
```
2. **Set up RLS policies**
- Create policies for user-owned data:
```sql
create policy "Users can manage own rows"
on answers for all
using (user_id = auth.uid())
with check (user_id = auth.uid());
```
- Repeat for all user-owned tables
3. **Apply migrations**
```bash
supabase db push
```
4. **Regenerate types after schema changes**
```bash
supabase gen types typescript --project-id <project-id> > supabase/types/database.ts
```
1. **Create auth screens**
- `app/(auth)/sign-in.tsx`
- `app/(auth)/sign-up.tsx`
- Use React Native Paper components (TextInput, Button, Surface)
- Implement React Hook Form + Zod validation
2. **Implement Supabase Auth integration**
```typescript
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});
```
3. **Set up auth state management**
- Create auth hook: `lib/hooks/useAuth.ts`
- Monitor auth state changes:
```typescript
supabase.auth.onAuthStateChange((event, session) => {
// Handle state changes
});
```
4. **Implement protected routes**
- Use expo-router's middleware pattern in `app/_layout.tsx`
- Redirect unauthenticated users to sign-in
1. **Set up TanStack Query**
- Create `lib/queryClient.ts`:
```typescript
import { QueryClient } from '@tanstack/react-query';
export const queryClient = new QueryClient({
defaultOptions: {
queries: { staleTime: 1000 * 60 * 5 },
},
});
```
2. **Create data hooks with React Query**
- Example for habits:
```typescript
export function useHabits() {
return useQuery({
queryKey: ['habits'],
queryFn: async () => {
const { data, error } = await supabase
.from('habits')
.select('*')
.order('created_at', { ascending: false });
if (error) throw error;
return data;
},
});
}
```
3. **Implement optimistic updates**
```typescript
const mutation = useMutation({
mutationFn: createHabit,
onMutate: async (newHabit) => {
await queryClient.cancelQueries({ queryKey: ['habits'] });
const previous = queryClient.getQueryData(['habits']);
queryClient.setQueryData(['habits'], (old) => [...old, newHabit]);
return { previous };
},
onError: (err, newHabit, context) => {
queryClient.setQueryData(['habits'], context.previous);
},
});
```
4. **Build feature screens**
- Use React Native Paper components consistently
- Implement forms with React Hook Form + Zod
- Add empty states and error handling
1. **Create AI Edge Function**
- Create `supabase/functions/ai/index.ts`:
```typescript
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
Deno.serve(async (req) => {
const { messages, model = "gpt-4o-mini", system } = await req.json();
const apiKey = Deno.env.get("OPENAI_API_KEY")!;
// Implement SSE streaming with AI SDK
const stream = await streamText({
model: { provider: "openai", name: model, apiKey },
messages,
system,
});
return new Response(stream.toReadableStream(), {
headers: { "Content-Type": "text/event-stream" },
});
});
```
2. **Set Edge Function secrets**
```bash
supabase secrets set OPENAI_API_KEY=your_key_here
```
3. **Deploy Edge Function**
```bash
supabase functions deploy ai
```
4. **Implement client-side streaming**
- Create hook for SSE streaming:
```typescript
export function useStreamAI() {
return useMutation({
mutationFn: async ({ messages, system }) => {
const response = await supabase.functions.invoke('ai', {
body: { messages, system },
});
// Handle SSE stream
},
});
}
```
1. **Install Superwall**
```bash
pnpm add @superwall/react-native-superwall
```
2. **Configure Superwall in app config**
- Update `app.config.ts` with Superwall plugin
- Add API key to env
3. **Initialize Superwall**
- Create `lib/superwall.ts`:
```typescript
import Superwall from '@superwall/react-native-superwall';
export function initSuperwall() {
Superwall.configure(env.EXPO_PUBLIC_SUPERWALL_KEY);
}
```
4. **Implement paywall trigger**
```typescript
await Superwall.register('premium_feature');
```
5. **Check entitlements**
```typescript
const hasAccess = await Superwall.checkEntitlement('premium');
```
6. **Gate premium features**
- Create HOC or hook to check entitlements
- Show paywall when needed
1. **Install dependencies**
```bash
pnpm add expo-notifications expo-device expo-constants
```
2. **Request permissions**
```typescript
import * as Notifications from 'expo-notifications';
const { status } = await Notifications.requestPermissionsAsync();
```
3. **Get Expo push token**
```typescript
const token = (await Notifications.getExpoPushTokenAsync()).data;
// Store in Supabase user profile
```
4. **Configure notification handling**
```typescript
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: false,
}),
});
```
1. **Install Sentry**
```bash
pnpm add @sentry/react-native
npx @sentry/wizard -i reactNative
```
2. **Install PostHog**
```bash
pnpm add posthog-react-native
```
3. **Initialize in app root**
```typescript
import * as Sentry from '@sentry/react-native';
import PostHog from 'posthog-react-native';
Sentry.init({ dsn: env.SENTRY_DSN });
const posthog = new PostHog(env.EXPO_PUBLIC_POSTHOG_KEY);
```
4. **Track key events**
```typescript
posthog.capture('habit_completed', { habit_id });
```
1. **Install EAS CLI**
```bash
pnpm add -g eas-cli
eas login
```
2. **Configure EAS Build**
```bash
eas build:configure
```
3. **Create preview builds**
```bash
eas build --platform ios --profile preview
eas build --platform android --profile preview
```
4. **Submit to TestFlight/Internal Testing**
```bash
eas submit --platform ios
eas submit --platform android
```
```bash
pnpm expo start # Start dev server
pnpm run android # Start Android
pnpm run ios # Start iOS
pnpm run web # Start web
supabase db push # Apply migrations
supabase gen types typescript --project-id <id> > supabase/types/database.ts
supabase functions deploy ai
supabase secrets set KEY=value
eas build --platform ios --profile preview
eas build --platform android --profile preview
eas submit --platform ios
eas submit --platform android
pnpm run lint # Lint code
pnpm run reset-project # Reset to clean slate
```
**Day 1: Foundation**
**Day 2: Core Features**
**Day 3: Polish & Ship**
1. **No native code** - Stay in managed workflow; avoid bare workflow unless absolutely necessary
2. **TypeScript everywhere** - No JavaScript files; backend Edge Functions are also TypeScript
3. **Paper only** - Don't mix UI libraries; avoid Tailwind/Nativewind to prevent style churn
4. **RLS first** - Always implement Row Level Security policies before client code
5. **Types from DB** - Regenerate Supabase types after every schema change
6. **Edge Functions for secrets** - Never expose API keys in client; use Edge Functions
7. **Minimal global state** - Prefer TanStack Query; use Zustand only for small UI state
8. **Zod contracts** - Define all API/DB contracts with Zod schemas
**Build failures:**
**Supabase connection issues:**
**Type errors:**
**Edge Function errors:**
**Auth issues:**
This starter template is designed to get you from idea to production in days, with AI assistance at every step. The opinionated stack choices reduce decision fatigue and make AI-assisted development more effective.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/expo-supabase-superwall-starter/raw