DEV Community

Cover image for 7 Lessons Shipping React Native Templates
Famitha M A
Famitha M A

Posted on • Originally published at applighter.com

7 Lessons Shipping React Native Templates

Seven React Native templates in one year, all on Expo SDK 54 + Supabase + NativeWind. This is the technical retrospective — seven lessons with code.

The templates

  • Weather ($49, 5 screens)
  • Fitness ($89, 12+ screens)
  • LearnHub ($89, 9 screens)
  • RideNow ($99, 8 screens)
  • Food Delivery ($79, 5 screens)
  • AI Voice Notes ($79, 16+ screens) — Whisper
  • Chat with PDF ($79, 16+ screens) — RAG

All share one substrate. That's the whole point.

Lesson 1 — Build the substrate before the first template

Weather was our first template. Five screens, no auth, no DB. It didn't need Supabase. We built it against Supabase anyway.

Rationale: template two would need auth, RLS, edge functions, and a marketing page contract. Building that infra for a template that didn't need it looked wasteful for two weeks. It paid for itself by template three.

If you want to build a template business, spend the first sprint on infra you won't use. It's the least glamorous advice I have.

Lesson 2 — API keys never live in the RN bundle

Both AI templates route through Supabase Edge Functions. The customer's OpenAI or Anthropic key sits at the edge. Client calls the function; function holds the key; RLS enforces per-user rate limits.

// Bad: key in the client
const openai = new OpenAI({ apiKey: EXPO_PUBLIC_OPENAI_KEY })

// Good: client calls edge function
const res = await fetch(`${SUPABASE_URL}/functions/v1/ai-chat`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${session.access_token}` },
  body: JSON.stringify({ messages }),
})
Enter fullscreen mode Exit fullscreen mode

EXPO_PUBLIC_* bakes into the bundle. Anyone can strings your .ipa and pull it out. This is not theoretical — it happens weekly to indie apps.

Lesson 3 — One data contract, all templates

Every template's marketing page on our site renders from the same TypeScript interface:

export interface ProductData {
  slug: string
  name: string
  tagline: string
  screenshots: Screenshot[]
  pricing: PricingTier[]
  features: Feature[]
  testimonials: Testimonial[]
  faqs: FAQ[]
  techStack: TechItem[]
}
Enter fullscreen mode Exit fullscreen mode

Sixty-three lines. Every template's config satisfies it. Every marketing component consumes it. Zero forks.

Before this contract, we had five copies of the pricing card. A fix on one wasn't a fix on all. After the contract: one component, one bug fix, seven templates updated.

Lesson 4 — Ship CLAUDE.md, AGENTS.md, .cursorrules

Every template ships with agent-readiness files. Short, opinionated, points to lib/data/types.ts and lists invariants.

Result: support tickets about "the agent broke something in your template" dropped noticeably. Not because agents got smarter — because they had a map.

Structure that works:

# CLAUDE.md
## Invariants
- Do not touch `lib/data/types.ts` — it's the shared contract
- Every new screen goes in `app/(tabs)/`, wired via Expo Router
- Edge functions in `supabase/functions/`, never in the client

## File map
- app/apps/config/*.config.ts — template configs
- app/apps/components/ — shared marketing UI
- app/apps/lib/data/ — data layer

## When adding a feature
1. Update the config type first
2. Then update the config value
3. Then update the UI that reads it
Enter fullscreen mode Exit fullscreen mode

Lesson 5 — Keep the entry price low

Templates range $49–$99. Temptation: raise everything to $99. Support-per-dollar is worse at $49.

Reality: $49 buyers come back for $79–$99 templates. The cheap template is a paid trial. Kill it and the funnel collapses.

Lesson 6 — Docs convert, not screenshots

Analytics: converting buyers spend more time in /docs than on the marketing page. Specifically the "how do I swap the AI provider" sections.

Writing docs first also forces you to design the escape hatch before the feature. If you can't write the "how do I swap this" section, the feature isn't done.

Lesson 7 — Stack review

Would pick again:

  • Expo SDK 54, RN 0.81 — new arch stable
  • NativeWind v4 — kills styling drift across templates
  • Supabase — auth, Postgres, edge, storage, one bill
  • TanStack Query v5 — replaced Redux everywhere
  • Expo Router v6 — file-based routing

Would skip:

  • Zustand for state that TanStack Query handles. Two templates had Zustand stores that were purely query-cache reinventions. Removing them cost more than not adding them.

For year two

  • Config file exists before any RN code does
  • Docs written before the feature
  • CLAUDE.md written during design

Related

Streaming AI Responses to React Native: The Complete Guide

Streaming AI Responses to React Native: The Complete Guide. Build fluid, conversational UIs with SSE, edge functions, & robust client-side rendering.

favicon applighter.com

React Native Supabase Template: Auth, RLS, Storage

How Applighter ships React Native templates with Supabase auth, RLS policies, and Storage already wired — clone, run migrations, build features.

favicon applighter.com

Top comments (0)