For dApps & ServicesLedger WalletContributing to Ledger WalletHow-to GuidesHow to Structure a Feature

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

ScenarioAction
Creating new featuresUse the new features/ folder structure (see below)
Working in MVVM codeFollow MVVM patterns — see MVVM Pattern reference
Working in legacy codeFollow existing patterns, but use MVVM for new components to ease future migration
RefactoringMigrate 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/
SubfolderPurpose
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:

ExtensionPlatform
.web.tsWeb and Desktop (Electron)
.native.tsReact Native (iOS + Android)
.ios.tsiOS only
.android.tsAndroid only
No extensionShared across all platforms

For example:

components/
├─ userInfo.ts           // Shared logic
├─ userInfo.web.ts       // Web/Desktop UI
├─ userInfo.native.ts    // Mobile UI
└─ userInfo.test.ts      // Tests
⚠️

Test 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 logic

Inject 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

Ledger
Copyright © Ledger SAS. All rights reserved. Ledger, Ledger Stax, Ledger Flex, Ledger Nano, Ledger Nano S, Ledger OS, Ledger Wallet, [LEDGER] (logo), [L] (logo) are trademarks owned by Ledger SAS.