The Based Native App Template is a production-ready React Native template designed to dramatically accelerate mobile app development. It combines a comprehensive component library, robust architecture patterns, and AI-guided customization through OpenSpec integration.
- Provide a clean, well-architected starting point for React Native apps
- Eliminate boilerplate setup and common architectural decisions
- Enable AI-assisted development through spec-driven workflows
- Support rapid customization while maintaining code quality
- Include best practices for performance, scalability, and maintainability
- React Native: 0.81.4 with New Architecture (JSI enabled)
- React: 19.1.0 (latest)
- TypeScript: 5.9.3 (strict mode enabled)
- Node: >=18, NPM: >=9
- @react-navigation/native: 7.1.18
- @react-navigation/bottom-tabs: 7.4.8
- @react-navigation/stack: 7.4.9
- Simple bottom tab navigation (Home + Settings)
- Stack navigation for onboarding flow
- React Context API with useReducer pattern
- No external state management libraries (Redux, MobX, Zustand)
- Contexts:
SettingsContext: Theme, preferences, app settingsNavigationContext: Navigation state managementToastContext: Toast notifications
- @nozbe/watermelondb: 0.28.0 - Reactive SQLite database with JSI
- react-native-mmkv: 3.3.3 - Fast key-value storage
- react-native-keychain: 10.0.0 - Secure credential storage
- Atomic Design Pattern: atoms → molecules → organisms → templates
- react-native-reanimated: 3.19.2 - Performant animations
- react-native-gesture-handler: 2.28.0 - Gesture system
- react-native-paper: 5.14.5 (icons only)
- react-native-vector-icons: 10.3.0
- react-native-safe-area-context: 5.6.1
- Theme System: Design tokens with light/dark modes
- @shopify/flash-list: 2.1.0 - Optimized list rendering
- react-native-fs: 2.20.0 - File system access
- react-native-device-info: 14.1.1 - Device information
- react-native-permissions: 5.4.2 - Permission management
- react-native-quick-crypto: 0.7.17 - Cryptography
- @notifee/react-native: 9.1.8 - Local notifications
- @biomejs/biome: 2.2.5 - Linter & Formatter (replaces ESLint/Prettier)
- Jest: 30.2.0 - Testing framework
- @testing-library/react-native: 13.3.3 - Component testing
- Formatter: Biome (configured in
biome.json) - Indentation: Tabs
- Quotes: Double quotes
- Line Length: 120 characters recommended
- Semicolons: Required
- Trailing Commas: ES5 style
- Components: PascalCase (
Button.tsx,SettingsDrawer.tsx) - Hooks: camelCase with "use" prefix (
useTheme,useSettings) - Contexts: PascalCase with "Context" suffix (
SettingsContext,ToastContext) - Types/Interfaces: PascalCase (
ButtonProps,SettingsState,Theme) - Constants: UPPER_SNAKE_CASE in
utils/constants/ - Files: Match component name exactly
- Functions: camelCase (
handlePress,calculateTotal)
- Strict mode enabled in
tsconfig.json - Explicit function return types preferred
- Interface over type for object definitions
- Const assertions for immutable data
- Enum-like unions:
type Theme = "light" | "dark" | "system" - Avoid
any- useunknownif type is truly unknown
Components are organized by complexity:
- atoms/: Basic building blocks (Button, Icon, Badge, ProgressBar)
- molecules/: Simple combinations (SearchBar, BottomNavContainer, DateSectionHeader)
- organisms/: Complex components (SettingsDrawer, HorizontalPageContainer)
- templates/: Page-level templates (OnboardingTemplate)
- Use React Context + useReducer for global state
- Keep state as local as possible
- Context structure:
// 1. Define types interface State { ... } type Action = | { type: 'ACTION_ONE' } | { type: 'ACTION_TWO' }; // 2. Create reducer function reducer(state: State, action: Action): State { ... } // 3. Create context const Context = createContext<{ state: State; dispatch: Dispatch<Action> }>(undefined); // 4. Create provider export function Provider({ children }) { ... } // 5. Create custom hook export function useContextName() { ... }
- Functional components only (no class components)
- Use hooks for logic reuse
useCallbackfor event handlers passed to childrenuseMemofor expensive computations- Props interface for all components
- Export named exports (not default) for components
- One component per file
- Co-locate styles with components using
StyleSheet.create() - Index files for barrel exports
- Keep related files together
- Unit tests for utilities and hooks
- Component tests for UI components
- Integration tests for user workflows
- Use
@testing-library/react-nativefor component tests
- Test files:
ComponentName.test.tsx - Describe blocks: Component/function name
- Test cases: "should [expected behavior] when [condition]"
- Critical paths: 100%
- Utilities: 90%+
- Components: 70%+
- Overall: 60%+
main: Production-ready codedevelop: Integration branchfeature/*: New featuresfix/*: Bug fixesrefactor/*: Code improvements
- Use conventional commits format
- Types:
feat,fix,docs,style,refactor,test,chore - Format:
type(scope): message - Examples:
feat(theme): add dark mode supportfix(navigation): resolve back button behaviordocs(readme): update installation instructions
This is a template project designed to be cloned and customized. It uses several systems to enable rapid customization:
Code contains placeholders that are replaced during setup:
{{APP_NAME}}- Application name{{APP_DISPLAY_NAME}}- Display name on device{{PACKAGE_NAME}}- Android package name{{BUNDLE_ID}}- iOS bundle identifier{{TABLE_NAME}}- Database table names{{PRIMARY_COLOR}}- Theme primary color- And more...
Special comment blocks guide AI assistants:
/* AI-INSTRUCTION-START:instruction-id
* Instructions for AI on how to customize this section
* AI-INSTRUCTION-END */These blocks:
- Mark customization points in the code
- Reference detailed instructions in
openspec/ai-instructions/ - Reference OpenSpec requirements
- Guide AI assistants on proper customization approach
The template.config.json file controls:
- Which modular features are enabled/disabled
- Project metadata and branding
- Domain-specific configuration
- OpenSpec integration settings
- Spec-driven development workflow
- AI-guided customization
- Change proposals for new features
- Documentation of requirements and scenarios
- Generic placeholder for domain entities
- Replace with actual business entities
- Located in
src/models/Item.ts - Database table:
{{TABLE_NAME}}
- Application-wide settings storage
- Key-value pairs in database
- Used for persistent configuration
- Located in
src/models/AppSettings.ts
- React Native Version: Must stay on 0.81.4 until dependencies support 0.82+
- New Architecture: JSI is enabled, all code must be JSI-compatible
- No Web Support: This is a native mobile template only
- TypeScript Required: No JavaScript files, strict TypeScript
- Minimum iOS: 13.0
- Minimum Android: API 24 (Android 7.0)
- Atomic Design: Must follow atom → molecule → organism → template hierarchy
- Theme System: All colors must come from theme, no hardcoded colors
- Design Tokens: Use spacing, borderRadius, etc. from
theme/colors.ts - Accessibility: All interactive elements must be accessible
- Bundle Size: Keep bundle size reasonable (< 50MB)
- Startup Time: App should launch in < 3 seconds
- Memory: Keep memory usage under 200MB on average
- Lists: Use FlashList for all lists with > 50 items
- Images: Optimize all images, use appropriate formats
- No Domain Logic: Template must remain domain-agnostic
- Placeholder Values: All customizable values must use
{{PLACEHOLDER}}format - AI Instructions: All customization points must have AI instruction blocks
- Documentation: All patterns must be documented for AI assistants
- Package Versions: Do NOT change package version numbers without testing
None - This template is designed to work offline and doesn't require external services.
Users can integrate:
- Analytics: Firebase, Mixpanel, Amplitude
- Crash Reporting: Sentry, Crashlytics
- Backend: Any REST API, GraphQL, Firebase
- Authentication: Auth0, Firebase Auth, custom
- Cloud Storage: AWS S3, Google Cloud Storage, Firebase Storage
- Custom Native Modules: Located in
src/native-modules/ - Turbo Modules: Specs in
src/specs/ - Platform Code:
android/andios/directories
- Check if feature should be modular (optional)
- If modular, add to
template.config.jsonfeatures section - Add AI instruction blocks at entry points
- Create OpenSpec proposal if significant
- Document in relevant AI instruction file
- Test with feature enabled AND disabled
- Run setup wizard (triggered automatically on first load)
- Answer questions or provide config file
- Wizard replaces placeholders
- Wizard removes disabled features
- Generate first OpenSpec change as example
- Start building domain-specific features
- AI reads
openspec/project.md(this file) first - AI checks
template.config.jsonfor configuration - AI follows instructions in
openspec/AGENTS.md - AI uses spec-driven approach via OpenSpec
- AI refers to
openspec/ai-instructions/for detailed guidance - AI creates proposals for significant changes
All AI instruction blocks in the codebase reference these files:
- data-model-creation.md: Creating WatermelonDB models and database schema
- screen-generation.md: Creating new screens following template patterns
- theme-customization.md: Customizing colors, fonts, and design tokens
- navigation-configuration.md: Adding screens to navigation
- context-creation.md: Creating new Context providers
- settings-configuration.md: Adding new app settings
- feature-flags.md: Working with the feature flag system
- component-creation.md: Creating atoms, molecules, organisms following Atomic Design
## Goal
Customize the template for your specific app - this is the FIRST thing you should do when starting with this template.
## Critical Files to Update
### 1. App Identity & Metadata
**app.json** - React Native app configuration
- `name`: "AppTemplate" → Your app's JS component name (e.g., "MyApp")
- MUST match MainActivity.kt's `getMainComponentName()`
- Must be a valid JavaScript identifier (no spaces, no special characters)
- `displayName`: "{{APP_NAME}}" → User-facing name (shown on home screen)
- `description`: "{{APP_DESCRIPTION}}" → Short app description
- `author`: "{{AUTHOR_NAME}}" → Your name or company
**package.json** - npm package configuration
- `name`: "app-template" → Your npm package name (lowercase, hyphens allowed)
- `description`: Update to match your app
### 2. Android Configuration
**android/app/build.gradle** - Android build settings
- `namespace`: "com.apptemplate" → Your package (e.g., "com.mycompany.myapp")
- `applicationId`: "com.apptemplate" → Same as namespace
- `versionCode`: 1 (increment for each release)
- `versionName`: "1.0.0" (user-facing version)
- Package name rules:
- All lowercase
- Use dots only (no hyphens, underscores, special characters)
- Typically: com.companyname.appname
**android/settings.gradle** - Gradle project name
- `rootProject.name`: 'AppTemplate' → Your app name
**android/app/src/main/res/values/strings.xml** - Android strings
- `app_name`: "{{APP_NAME}}" → Your app's display name
**android/gradle.properties** - Release signing configuration
- `APP_UPLOAD_STORE_FILE`: "release.keystore" → Your keystore filename
- `APP_UPLOAD_KEY_ALIAS`: "app-key-alias" → Your key alias
- `APP_UPLOAD_STORE_PASSWORD`: Update with your keystore password
- `APP_UPLOAD_KEY_PASSWORD`: Update with your key password
- See "Release Keystore Setup" section below for detailed instructions
**android/app/src/main/java/com/visara/** - Java/Kotlin package structure
- Rename directory to match your package name
- Example: com.visara → com.mycompany.myapp
- Update all package declarations in:
- MainActivity.kt
- MainApplication.kt
- MemoryModule.java
- MemoryPackage.java
**MainActivity.kt** - Main activity
- Package declaration: `package com.visara.app` → Your package
- Component name: `getMainComponentName()` → Return "AppTemplate" or your app name
- MUST match app.json "name" field exactly
**MainApplication.kt** - Application class
- Package declaration: `package com.visara.app` → Your package
- Import statements: Update to match your package
### 3. Storage & Encryption IDs
**src/services/storage/mmkv.ts** - MMKV storage config
- `id`: "{{PACKAGE_NAME}}-storage" → Your package name
**src/services/security/EncryptionService.ts** - Encryption config
- `ENCRYPTION_KEY_ALIAS`: "{{PACKAGE_NAME}}_encryption_key" → Your package name
### 4. Template Configuration
**template.config.json** - Complete all sections
- Fill out all `{{PLACEHOLDER}}` values
- Set `template.configured = true` when done
- Configure features you want to use
### 5. Icon Assets (Optional - can do later)
Replace default icons in:
- `android/app/src/main/res/mipmap-*/` - All app_launcher* files
- `android/app/src/main/res/mipmap-anydpi-v26/app_launcher.xml` - Adaptive icon config
### 6. Release Keystore Setup (REQUIRED for Production)
**Generate Release Keystore:**
```bash
cd android/app
keytool -genkeypair -v -storetype PKCS12 -keystore release.keystore \
-alias app-key-alias -keyalg RSA -keysize 2048 -validity 10000You will be prompted for:
- Keystore password (SAVE THIS SECURELY!)
- Key password (typically same as keystore password)
- Your name/organization details
Update Configuration:
Edit android/gradle.properties:
APP_UPLOAD_STORE_FILE=release.keystore
APP_UPLOAD_KEY_ALIAS=app-key-alias
APP_UPLOAD_STORE_PASSWORD=your_secure_password
APP_UPLOAD_KEY_PASSWORD=your_secure_passwordSecurity Checklist:
- Keystore file created and placed in
android/app/ - Keystore backed up to secure location (outside of project)
- Passwords updated in
gradle.properties -
gradle.propertiesadded to.gitignore(if not using placeholder passwords) - Documented keystore password in secure password manager
CRITICAL: If you lose the keystore file, you cannot update your published app on Google Play!
Replace default icons with your app's icons:
Android Icons:
android/app/src/main/res/mipmap-hdpi/- All densitiesandroid/app/src/main/res/mipmap-mdpi/android/app/src/main/res/mipmap-xhdpi/android/app/src/main/res/mipmap-xxhdpi/android/app/src/main/res/mipmap-xxxhdpi/android/app/src/main/res/mipmap-anydpi-v26/- Adaptive icon config
iOS Icons:
ios/[AppName]/Images.xcassets/AppIcon.appiconset/
Tip: Use a tool like Icon Kitchen to generate all required sizes.
Update colors and branding:
src/theme/colors.ts- Primary, secondary, accent colors- Update to match your brand guidelines
When changing from "com.visara.app" to your package (e.g., "com.mycompany.myapp"):
- android/app/build.gradle - namespace and applicationId
- android/settings.gradle - rootProject.name
- Rename directory: android/app/src/main/java/com/visara/ → com/mycompany/myapp/
- MainActivity.kt - package declaration and getMainComponentName()
- MainApplication.kt - package declaration and imports
- MemoryModule.java - package declaration
- MemoryPackage.java - package declaration
- app.json - name field
- src/services/storage/mmkv.ts - storage ID
- src/services/security/EncryptionService.ts - encryption key alias
After customization:
-
Build Check
npm run typecheck npm run android
-
Verify App Name
- Check home screen shows correct display name
- Check app switcher shows correct name
-
Verify Package Name
- No build errors
- App installs correctly
- No component registration errors
-
Test Core Features
- Database initialization works
- Settings persist
- Navigation works
- Theme switching works
### Workflow 1: Adding a New Screen
```markdown
## Goal
Add a "Profile" screen to the app
## Steps
1. **Create Screen Component**
- File: `src/screens/Profile/ProfileScreen.tsx`
- Follow HomeScreen.tsx pattern
- Add AI instruction blocks for customization points
- Use theme system for styling
2. **Add to Navigation**
- Update `src/navigation/MainNavigator.tsx`
- Add tab to bottom navigator
- Choose appropriate icon
- Add to type definitions
3. **Create Context (if needed)**
- File: `src/contexts/ProfileContext.tsx`
- Follow SettingsContext.tsx pattern
- Add to App.tsx providers
4. **Add Data Model (if needed)**
- File: `src/models/Profile.ts`
- Update `src/services/database/schema.ts`
- Update `src/services/database/database.ts`
- Increment schema version if modifying existing DB
5. **Create OpenSpec Proposal**
- `openspec/changes/add-profile-screen/proposal.md`
- Document requirements, scenarios, implementation
6. **Test**
- Navigation works
- Data persists
- Theme applies correctly
- Follows template patterns
## Goal
Apply custom brand colors to the template
## Steps
1. **Update template.config.json**
```json
"branding": {
"theme": {
"primaryColor": "#6200EE",
"secondaryColor": "#03DAC6",
"accentColor": "#FF0266"
}
}-
Apply to theme/colors.ts
- Update
colors.primary,colors.secondary,colors.accent - Update derived colors if needed
- Test in both light and dark modes
- Update
-
Verify Application
- Check all buttons use primary color
- Check accents and highlights
- Verify contrast ratios for accessibility
- Test throughout app screens
-
Update Assets
- App icon with new colors
- Splash screen
- Any branded images
### Workflow 3: Creating a Data Model
```markdown
## Goal
Add a "Task" model for a todo app
## Steps
1. **Define Model**
```typescript
// src/models/Task.ts
export class Task extends Model {
static table = 'tasks';
@field('title') title!: string;
@field('completed') completed!: boolean;
@field('due_date') dueDate?: number;
@readonly @date('created_at') createdAt!: Date;
@readonly @date('updated_at') updatedAt!: Date;
}
-
Update Schema
// src/services/database/schema.ts tableSchema({ name: 'tasks', columns: [ { name: 'title', type: 'string', isIndexed: true }, { name: 'completed', type: 'boolean', isIndexed: true }, { name: 'due_date', type: 'number', isOptional: true }, { name: 'created_at', type: 'number' }, { name: 'updated_at', type: 'number' }, ], })
-
Register Model
// src/services/database/database.ts import { Task } from '@models/Task'; modelClasses: [Task, AppSettings]
-
Create Repository
// src/services/database/TaskRepository.ts export class TaskRepository { async getAllTasks() { ... } async createTask(data) { ... } async updateTask(id, data) { ... } async deleteTask(id) { ... } }
-
Update Schema Version
- Increment version in schema.ts
- Add migration if modifying existing database
---
## Quick Reference
### Path Aliases
```typescript
@components/* → ./src/components/*
@screens/* → ./src/screens/*
@services/* → ./src/services/*
@contexts/* → ./src/contexts/*
@models/* → ./src/models/*
@hooks/* → ./src/hooks/*
@utils/* → ./src/utils/*
@shared-types/* → ./src/shared-types/*
@native-modules/* → ./src/native-modules/*
@specs/* → ./src/specs/*
@theme/* → ./src/theme/*
@navigation/* → ./src/navigation/*
# Development
npm start # Start Metro bundler
npm run android # Run on Android
npm run ios # Run on iOS
# Build
npm run apk # Build Android APK
npm run aab # Build Android Bundle
# Code Quality
npm run typecheck # TypeScript checking
npm run lint # Lint with Biome
npm run lint:fix # Fix linting issues
npm run format # Format code
npm test # Run tests
# Template
npm run wizard # Run setup wizard
npm run validate-config # Validate template.config.jsontemplate.config.json- Template configurationopenspec/project.md- This file (project context)openspec/AGENTS.md- AI assistant instructionssrc/theme/colors.ts- Design tokenssrc/services/database/schema.ts- Database schemasrc/navigation/RootNavigator.tsx- App navigationpackage.json- Dependencies (DO NOT change versions without testing)
Remember: This is a template. Everything marked with {{PLACEHOLDERS}} or AI instruction blocks is meant to be customized for your specific project. Follow the OpenSpec workflow for significant changes.