How to Structure a Feature
This guide shows you how to organize your code depending on the scenario you are working in.
Migration in Progress: The codebase contains legacy, MVVM, and feature-first code. Follow the guidance below based on your scenario.
Choose your scenario
| Scenario | Action |
|---|---|
| Creating new features | Use the new features/ folder structure (see below) |
| Working in MVVM code | Follow MVVM patterns — see MVVM Pattern reference |
| Working in legacy code | Follow existing patterns, but use MVVM for new components to ease future migration |
| Refactoring | Migrate code to the feature-first architecture when scope allows |
Create a new feature
If you are creating a new feature, place it in the features/ folder at the monorepo root.
1. Create the feature folder
features/
└─ {featureName}/
├─ components/
├─ screens/
├─ data-layer/
├─ routes/
├─ hooks/
└─ utils/| Subfolder | Purpose |
|---|---|
components/ | Reusable UI components within the feature |
screens/ | Screen-level components (can have their own components/ subfolder) |
data-layer/ | State management: entities, slices, selectors, actions, API |
routes/ | Platform-agnostic routing abstraction |
hooks/ | Feature-specific custom hooks |
utils/ | Feature-specific utilities |
2. Add platform-specific files
Use file extensions to target specific platforms within each feature folder:
| Extension | Platform |
|---|---|
.web.ts | Web and Desktop (Electron) |
.native.ts | React Native (iOS + Android) |
.ios.ts | iOS only |
.android.ts | Android only |
| No extension | Shared across all platforms |
For example:
components/
├─ userInfo.ts // Shared logic
├─ userInfo.web.ts // Web/Desktop UI
├─ userInfo.native.ts // Mobile UI
└─ userInfo.test.ts // TestsTest files (*.test.ts) should always be colocated with their source files.
3. Use the MVVM pattern for components
For components that connect to Redux, make API calls, or contain complex logic, create a dedicated ViewModel hook:
ComponentName/
├─ index.tsx # Exports the connected component
└─ useComponentNameViewModel.ts # Contains business logicInject the ViewModel result as props to the View — see the MVVM Pattern reference for the full implementation pattern.
4. Respect import boundaries
Apps can import from features, but features should not import from apps. See the Architecture reference for the full import rules.
Work within existing MVVM code
If you are modifying code in apps/*/src/mvvm/, follow the existing ViewModel pattern. For any new components you add, use the MVVM Pattern with the correct props-injection approach.
Work within legacy code
If you are modifying legacy code in apps/*/src/ (outside mvvm/), follow the existing patterns in that area. When adding new components, prefer the MVVM pattern to ease future migration.
Refactor legacy code
When refactoring legacy code with sufficient scope, migrate it to the feature-first architecture in features/. Coordinate with Product for major feature reworks.
See also
- Architecture reference — Full folder structure, import rules, platform extensions
- MVVM Pattern reference — ViewModel implementation and when to use it
- Do’s and Don’ts — 9 numbered rules for naming and structure
- Architecture Decisions — Why we adopted this architecture