Field Stack
The Non-Technical Founder's App Stack
Every config file, every Cursor rule, every build shortcut. The exact stack DreamLaunch uses to ship production mobile apps in under 5 weeks.

Harshil Tomar
Founder, DreamLaunch
June 25, 2026
Field Stack / 2026 Edition — DreamLaunch Studio
The Non-Technical Founder's App Stack.
Every config file. Every Cursor rule. Every build shortcut. The exact system we use to get a production mobile app shipped in under 5 weeks.
10+ Apps shipped |
5 wks Zero to live |
5+ Generating revenue |
This isn't a framework doc. These are the exact files we open on day one of every build. Copy them. The opportunity right now — particularly on the App Store and Play Store — is real, and it's sitting unclaimed while most founders are still arguing about which tech stack to use.
Use this. Ship before someone else does.
Why right now is the window.
Both stores changed the rules in 2026. If you shipped before this, you played a different game. The non-technical founder's path just got meaningfully shorter.
App Store — what changed
| Change | What it means for you |
| Editorial featuring expanded to solo developers | Apple's Today tab now runs dedicated "Indie Spotlight" slots. A well-designed app from a solo founder can get the same feature placement as a funded startup. Design quality is the only criteria — not installs. |
| Custom product pages (CPPs) now searchable | You can create up to 35 alternate app store pages, each targeting a different search intent. Before 2026 these were ad-only. Now they rank organically. |
| Review response time now a ranking signal | Apps that respond to reviews within 24 hrs get a visibility boost in browse and search. Automated response tooling now counts. |
Play Store — what changed
| Change | What it means for you |
| LiveOps events surface in search | In-app events and feature drops now appear directly in Play Store search results. Running a weekly event (even a simple "new content drop") boosts discovery without paid spend. |
| Engagement-weighted ranking update | Google shifted ranking weight toward session frequency and retention. A small app with high daily engagement beats a large app with low return rate. |
| Pre-registration conversion now tracks to rank | Pre-registration conversion rate is now a day-one ranking input. Building a waitlist before launch directly improves your initial rank velocity. |
|
The window is 12–18 months. Every meaningful platform change like this has a window before the larger studios and well-funded teams adapt and flood in. You're inside that window right now. The founders who ship in the next 90 days will have an organic head start that money can't easily replicate later. |
The full stack.
These are the exact tools across every build. No variation. Consistency here is the shortcut — the stack is already configured, already documented, already debugged. You pick it up and build.
Core layer
One codebase, both platforms. Expo SDK 52 removes most of the friction that made RN frustrating two years ago. EAS Build handles store submissions.
FrameworkNon-negotiable. Strict mode catches the class of bug that kills a launch timeline. Every file. No exceptions.
LanguageTailwind CSS for React Native. Eliminates the styling context switch between web and mobile. Same class names, same mental model.
StylingFile-based routing. Same pattern as Next.js. Deep links, shared routes, and universal links all configured from the file structure.
NavigationBackend layer
Postgres + auth + storage + realtime in one. The row-level security model maps directly to how mobile apps need to scope data per user.
Database + AuthSupabase edge functions for any server-side logic. No separate backend deployment. Runs globally, cold-starts under 100ms.
ServerlessProduct + revenue layer
Handles all subscription logic across iOS and Android. Paywalls, trial periods, restore purchases, and webhook events for both stores — single SDK.
MonetizationSelf-hosted analytics, feature flags, and session replay. GDPR-compliant. Connects directly to the funnel events that matter: onboarding completion, paywall view, conversion.
AnalyticsPush notification infrastructure built into Expo. Handles APNs and FCM registration, scheduling, and deep-link routing from notification tap.
EngagementError monitoring + crash reporting. Catches the issues in production that never surfaced in testing. Source maps configured via EAS.
MonitoringDev tooling
AI-first editor. The rules in Section 03 are what make it understand your stack without constant correction. Setup once, works across every file.
EditorCloud builds for iOS and Android. Manages certificates, provisioning profiles, and store submission. Eliminates the Xcode dependency for iOS builds.
CI/CDCursor rules.
Cursor is only as useful as the rules you give it. Without a project rules file, it guesses at your stack, your conventions, and your preferences — and guesses wrong often enough to slow you down. With these rules, it generates components that drop into the project without correction.
Create .cursorrules in the root of your project and paste the following. Do not trim it — every line is there because we removed something that caused a problem.
# DreamLaunch Mobile Stack — Cursor Project Rules # Stack: React Native + Expo SDK 52 + TypeScript (strict) + NativeWind v4 + Supabase + Expo Router v3 You are an expert React Native developer. Always use TypeScript with strict mode. Never use 'any'. Never use class components. Always use functional components with hooks. ## Framework rules - Use Expo SDK 52. Never use bare React Native unless I ask. - Use Expo Router v3 for all navigation. No React Navigation. - File-based routing lives in /app directory. - Shared components live in /components. Screens live in /app. - Use NativeWind v4 for all styling. No StyleSheet.create() unless unavoidable. - Tailwind classes only — no inline style objects for layout. ## Data + auth - Use Supabase for all database operations. - Import the Supabase client from @/lib/supabase. - Always use row-level security. Never expose the service role key client-side. - Auth state lives in a context at @/context/AuthContext. - Use Supabase realtime subscriptions for live data — not polling. ## Component conventions - Component files use PascalCase. Utility files use camelCase. - Export components as named exports, not default. - Props interfaces defined above the component, named [ComponentName]Props. - Use React.memo() for list item components only. - No prop drilling beyond 2 levels — use context or Zustand. ## State management - Local UI state: useState. - Cross-component state: Zustand stores in /store directory. - Server state: TanStack Query (React Query) with Supabase fetcher. - Never store auth tokens manually — use Supabase session. ## Payments - RevenueCat SDK is the only payment handler. Import from react-native-purchases. - Paywall component lives at @/components/Paywall.tsx. - Always check entitlement status before showing premium features. - Never implement custom receipt validation. ## Error handling - Use Sentry.captureException() for all caught errors in production paths. - User-facing errors show a toast (via Burnt library), not an alert(). - Never swallow errors silently. ## Performance - FlashList instead of FlatList for all scrollable lists. - Images use expo-image, not the built-in Image component. - Use useMemo and useCallback only when profiling shows it helps. - Avoid anonymous functions in JSX render paths for list items. ## File generation When creating a new screen, always include: 1. Types file alongside the screen 2. A loading state 3. An error state 4. A proper KeyboardAvoidingView if the screen has inputs
|
Update the rules as the project grows. Add a new rule every time Cursor gives you a wrong answer twice in a row. The rules file is a living document — treat it like internal documentation. By week 5, it will encode everything specific about your app that Cursor needs to generate production-ready code. |
Core config files.
These files go into every project on day one. They take 20 minutes to set up manually. We've extracted the templates here so you copy, adjust the two or three values specific to your app, and move on.
app.config.ts — Expo config
import { ExpoConfig, ConfigContext } from 'expo/config';
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
name: 'Your App Name',
slug: 'your-app-slug',
version: '1.0.0',
orientation: 'portrait',
icon: './assets/icon.png',
scheme: 'yourapp', // deep link scheme
userInterfaceStyle: 'automatic', // supports dark mode
splash: {
image: './assets/splash.png',
resizeMode: 'contain',
backgroundColor: '#ffffff',
},
ios: {
supportsTablet: false,
bundleIdentifier: 'com.yourcompany.yourapp',
buildNumber: '1',
infoPlist: {
NSCameraUsageDescription: 'Used for profile photos',
},
},
android: {
package: 'com.yourcompany.yourapp',
versionCode: 1,
adaptiveIcon: {
foregroundImage: './assets/adaptive-icon.png',
backgroundColor: '#ffffff',
},
permissions: ['CAMERA', 'READ_EXTERNAL_STORAGE'],
},
plugins: [
'expo-router',
'expo-notifications',
['expo-image-picker', { photosPermission: '...' }],
['@sentry/react-native/expo', { organization: '...', project: '...' }],
],
extra: {
supabaseUrl: process.env.EXPO_PUBLIC_SUPABASE_URL,
supabaseAnonKey: process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY,
revenueCatApiKey: process.env.EXPO_PUBLIC_REVENUECAT_KEY,
eas: { projectId: 'your-eas-project-id' },
},
});
lib/supabase.ts — client setup
import { createClient } from '@supabase/supabase-js';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AppState } from 'react-native';
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!;
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
storage: AsyncStorage,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
});
// Keep session alive when app returns from background
AppState.addEventListener('change', (state) => {
if (state === 'active') supabase.auth.startAutoRefresh();
else supabase.auth.stopAutoRefresh();
});
eas.json — build profiles
{
"cli": { "version": ">= 7.0.0" },
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"env": { "APP_ENV": "development" }
},
"preview": {
"distribution": "internal",
"env": { "APP_ENV": "preview" },
"ios": { "simulator": false }
},
"production": {
"autoIncrement": true,
"env": { "APP_ENV": "production" }
}
},
"submit": {
"production": {
"ios": { "appleId": "your@email.com", "ascAppId": "YOUR_APP_ID" },
"android": { "serviceAccountKeyPath": "./google-play-key.json", "track": "internal" }
}
}
}
Build shortcuts.
Every command that runs more than twice a week gets a shortcut. These are the package.json scripts we add to every project, plus the shell aliases that make the day-to-day flow fast without memorising flags.
package.json scripts
{
"scripts": {
// Dev
"start": "expo start",
"ios": "expo start --ios",
"android": "expo start --android",
"dev-client": "expo start --dev-client",
// Type checks
"type-check": "tsc --noEmit",
"lint": "eslint . --ext .ts,.tsx --fix",
// EAS builds
"build:dev": "eas build --profile development --platform all",
"build:preview": "eas build --profile preview --platform all",
"build:prod": "eas build --profile production --platform all",
"build:ios": "eas build --profile production --platform ios",
"build:android": "eas build --profile production --platform android",
// Submissions
"submit:ios": "eas submit --platform ios",
"submit:android":"eas submit --platform android",
"submit:all": "eas submit --platform all",
// Updates (OTA)
"update": "eas update --branch production --message",
"update:staging":"eas update --branch preview",
// Database
"db:types": "supabase gen types typescript --linked > types/supabase.ts",
"db:push": "supabase db push",
"db:reset": "supabase db reset"
}
}
Shell aliases (add to .zshrc / .bashrc)
# Expo shortcuts alias es="expo start" alias ec="expo start --dev-client" alias ecl="expo start --clear" # EAS one-liners alias bp="eas build --profile production --platform all" alias bios="eas build --profile production --platform ios" alias band="eas build --profile production --platform android" alias sub="eas submit --platform all" # Supabase alias dbt="supabase gen types typescript --linked > types/supabase.ts" alias sbstart="supabase start" alias sbstop="supabase stop" # OTA push (usage: ota "fix login bug") ota() { eas update --branch production --message "$1"; }
The OTA deployment rule
EAS Update (over-the-air updates) lets you push JS changes to users without a new store submission. Use it aggressively for bug fixes, copy changes, and feature flags. The one rule: never use OTA to update native modules or permissions — those require a full build.
| Change type | OTA? | Requires build? |
| Bug fix in JS logic | ✓ Yes — ship in minutes | No |
| UI / copy changes | ✓ Yes | No |
| New screen (JS only) | ✓ Yes | No |
| New native module / SDK | ✗ No | Yes — EAS Build |
| Permission changes | ✗ No | Yes — new store submission |
| Splash screen / icon change | ✗ No | Yes — new store submission |
The 5-week map.
This is how 10+ apps went from idea to live in under 5 weeks. The sequence matters as much as the tasks. Week 4 is usually where founders want to start. Starting in Week 4 is why most founders are still building 6 months later.
One landing page. One clear promise. Real email signups from real people in the target market. The metric is 50+ signups before writing a line of code. If you can't get 50 signups from a landing page, the app won't get downloads either. Set up Supabase project, configure EAS, scaffold the repo.
Supabase auth live. The one core action the app exists to do — and only that. No settings screen, no profile page, no social features. The core loop is: user arrives → user does the thing → user gets the value. Ship nothing else until the core loop is done and feels right.
RevenueCat live. Paywall built and tested on both platforms. Push notifications configured with at least one re-engagement trigger (e.g., streak break, new content). PostHog events firing on: onboarding complete, paywall view, trial start, conversion. These events are non-negotiable — you can't improve what you can't see.
This is the only week where the output is screenshots, not code. App Store and Play Store screenshots drive 60–70% of conversion from impression to install. Custom product pages configured for the top 3 search intents. App preview video recorded. Review prompt configured to fire after the first successful core-loop completion.
Submit to both stores. Target the first 100 users from the waitlist you built in Week 1 — not from paid ads. Waitlist users convert at 40–60%. Paid cold traffic converts at 2–5%. Reply to every review in the first 30 days. Run the first LiveOps event on Play Store within 7 days of launch. Watch the PostHog funnel daily.
|
The rule we give every founder we work with: If a feature doesn't appear in the 5-week map, it doesn't exist yet. Defer it. Write it in a doc. Ship the 5-week version first. You can always add. You can't unship late. |
Revenue setup.
The difference between an app that generates revenue and one that doesn't is usually not the product. It's whether the revenue infrastructure was built in Week 3 or Week 7. By Week 7, the founder is tired, the motivation is lower, and "we'll add payments later" has become a six-month delay.
RevenueCat setup checklist
| Step | Where | Notes |
| Create products in App Store Connect | App Store Connect → In-App Purchases | Create at minimum: monthly sub, annual sub. Name them clearly — reviewers read these. |
| Create products in Play Console | Play Console → Monetize → Subscriptions | Mirror the same product IDs as iOS. RevenueCat maps them as one entitlement. |
| Add products to RevenueCat dashboard | app.revenuecat.com | Create one Entitlement (e.g. "premium"). Add both iOS + Android products to it. |
| Configure offerings | RevenueCat → Offerings | The "default" offering is what the SDK serves to the paywall automatically. |
| Test on sandbox | iOS Simulator + sandbox Apple ID | Sandbox purchases don't charge. Test full purchase → restore → entitlement check flow. |
The paywall timing rule
Most apps show the paywall too early (on first open) or too late (never, until the user finds the locked feature). The pattern that works across our builds:
- Show the paywall after the first successful core-loop completion — the user has just got the value, motivation to pay is highest
- Offer a 3-day free trial — trial users convert at 2–3× the rate of direct purchases, and the churn difference is minimal
- Price anchoring: show the annual plan first, prominently, with per-month equivalent. Monthly plan below it
- Never gate onboarding — users who don't finish onboarding don't pay either
Revenue benchmarks to aim for by week 8
2–5% Trial → paid conversion |
40–60% Waitlist → install rate |
Day 7 First paying user target |
If you're below these numbers in week 8, the issue is almost always one of three things: the paywall timing, the pricing anchor, or the trial length. Change one variable at a time. PostHog's funnel view shows exactly where users drop.
|
The $100K/mo path from here. $100K/month from a subscription app is ~3,300 monthly subscribers at $30/month, or ~830 annual subscribers at $120/year. With the 2026 store changes giving organic reach to well-designed small apps, this number is reachable in 12–18 months from a cold start. It requires: strong retention (D30 > 25%), a paywall that converts, and consistent LiveOps events to maintain store visibility. None of those things require a large team. They require building the right infrastructure in the first 5 weeks. |
DreamLaunch Studio — dreamlaunch.studio — All metrics from internal builds, 2024–2026.
Our Work
Book a Call


