An opinionated production starter for React Native apps β strict TypeScript, Redux Toolkit, stack navigation, MMKV-backed persistence, Unistyles theme tokens, i18n, shared UI primitives, and small app-facing adapters around native capabilities.
It ships an AGENTS.md / CLAUDE.md pair, four vendored skills, and a plugin
registration for the rest, so coding agents get the project's conventions and
procedures the moment you generate an app. See
π Companion skills.
npx @react-native-community/cli@latest init MyApp \
--template https://github.com/ltatarev/react-native-template.gitMake sure your machine is ready for React Native development, then create a new app from the template:
npx @react-native-community/cli@latest init MyApp --template https://github.com/ltatarev/react-native-template.gitReplace MyApp with your app name. If npx asks to install
@react-native-community/cli, confirm with y.
Do not use npx react-native init; React Native now treats that command as
deprecated and exits before creating the app.
Current template runtime:
- React Native
0.87.0 - React
19.2.7 - Node.js
>=22.11.0 - Yarn
4.17.0 - Ruby
2.7.7 - CMake for iOS/Hermes pods
From a generated app or the template/ directory in this repository:
corepack enable
yarn
bundle install
yarn install-podsRun the app:
yarn start
yarn ios
yarn android| Script | Purpose |
|---|---|
yarn lint |
Run ESLint flat config. |
yarn tsc |
Run strict TypeScript without emitting files. |
yarn test:unit |
Run the unit Jest harness. |
yarn madge |
Check circular dependencies. |
yarn madge:image |
Generate a dependency graph image. |
yarn sanity |
Run lint, TypeScript, and Madge checks. |
yarn install-pods |
Install iOS Pods through Bundler. |
src/
βββ common/ # Pure shared hooks, types, helpers
βββ modules/
β βββ design-system/ # Primitive gallery (development only)
β βββ feature-flag/ # Typed boolean gates
β βββ home/ # Neutral reference feature
β βββ main/ # App shell and root navigator
β βββ navigation/ # Route helpers, screen options, navigation ref
β βββ onboarding/ # First-run gate
β βββ redux/ # Store, persistor, typed hooks
β βββ settings/ # Appearance and about
βββ theme/
β βββ redux/ # Persisted appearance mode
β βββ ui/ # Shared UI primitives
β βββ gutter.ts # Device metrics
β βββ scales.ts # Spacing, radii, type, motion, size, z-index
β βββ styles.ts
β βββ theme.ts # The two palettes
β βββ types.ts
β βββ unistyles.ts
βββ utils/
βββ app-state/
βββ error-handling/
βββ haptic-feedback/
βββ logger/
βββ services/
βββ storage/
βββ toast.tsx
i18n/
βββ en_EN.json
βββ index.ts
βββ resources.ts
The codebase is package-by-feature. Feature modules live under
src/modules/<feature> and expose their public API through
src/modules/<feature>/index.ts.
Cross-module imports should use the public module surface:
import { HomeScreen } from 'modules/home';Do not reach into another module's internals:
import { HomeScreen } from 'modules/home/screens/HomeScreen';ESLint enforces this with no-restricted-imports.
Aliases are configured in both TypeScript and Babel.
| Alias | Resolves to |
|---|---|
assets/* |
src/assets/* |
common/* |
src/common/* |
modules/* |
src/modules/* |
theme/* |
src/theme/* |
utils/* |
src/utils/* |
Styling uses react-native-unistyles.
- Import
StyleSheetfromreact-native-unistyles. - Keep shared primitives in
src/theme/ui. - Use tokens from
theme.ts(the two palettes) andscales.ts(gutter, typography, radii, motion, size, shadow, z-index). - Avoid color literals in feature UI.
- Appearance is
system/light/dark, persisted intheme/reduxand pushed into Unistyles byuseAppearanceSync.
Example:
const styles = StyleSheet.create(theme => ({
title: {
color: theme.colors.text,
fontSize: theme.typography.fontSize.lg,
marginBottom: theme.gutter.md,
},
}));- Root store setup lives in
src/modules/redux. - Use
useAppDispatchanduseAppSelectorfrommodules/redux. - Feature state uses Redux Toolkit slices and selectors.
- Redux persistence uses MMKV through
utils/storage.
i18n is initialized from src/index.ts.
- Resources live in
i18n/en_EN.json. - Components use
useTranslation()fromreact-i18next. - User-facing feature text should render through
t(...).
Feature code should not import native SDKs directly. Use the app-facing
adapters in src/utils:
utils/storageβ Redux Persist storage, plusappPreferencesfor values read before the first frameutils/toastutils/loggerutils/error-handlingutils/haptic-feedbackutils/app-stateβ foreground/background transitionsutils/servicesβ platform checks, app version
docs/growing-the-app.md describes the shape each of the common next
capabilities takes β bottom tabs, native sheets, notifications, SQLite, image
picking, widgets, subscriptions β none of which the template installs.
theme/ui ships the set every app re-derives otherwise:
Screen, Text, View, Row, Touchable, Button, IconButton, Icon,
Card, Divider, Pill, SectionHeader, EmptyState, Skeleton,
ProgressBar, Switch, TextInput, Sheet, ConfirmDialog, LoadingScreen,
StatusBar, KeyboardAwareScrollView, plus the toast viewport.
modules/design-system's gallery screen renders all of them in the live theme β
add a new primitive there, and review both themes in one pass. Motion presets
(usePressScale, useModalPresence) come from theme/ui/motion.ts and every
animation honors Reduce Motion.
- Create
src/modules/<name>/const.tswithMODULE_NAMEand route names built fromRouteService.constructRouteName. - Create
src/modules/<name>/index.tsas the public surface. - Add screens under
screens/, built fromtheme/uiprimitives. - Add Redux slice/selectors under
redux/if the module owns state. - Register the reducer in
modules/redux/store.tswhen needed. - Register routes in
modules/main/navigator.tsx. - Add text keys to
i18n/en_EN.json. - Export only the API other modules need from the module barrel.
A route name two modules both need goes in modules/navigation/routes.ts, which
depends on nothing β that is what keeps sibling features from importing each other
just to navigate.
Template-specific guidance ships inside the project so agents pick it up from a generated app's root:
template/AGENTS.md/template/CLAUDE.mdβ conventions, anti-patterns, commandstemplate/CONTEXT.mdβ vocabulary and module boundariestemplate/docs/growing-the-app.mdβ the shape each common next capability takestemplate/.claude/skills/β vendored skills:add-feature,build-ui,validate-change,rozenite-agenttemplate/.claude/settings.jsonβ registers the rest of the library as a plugin
See π Companion skills for how the two fit together.
ltatarev/skills β the adora plugin β
is a Claude Code marketplace of agent skills that encode this template's
conventions: building UI, scaffolding feature modules, writing tests, validating
changes, iOS widgets, launch screens, plus a commit and ticket workflow set.
Paired with this template they need no configuration β the module anatomy, the
theme/ui kit, and the Jest unit harness they target are all already here.
A generated app gets them two ways.
Vendored. add-feature, build-ui and validate-change are copied into
template/.claude/skills/ and pinned in template/skills-lock.json, alongside
rozenite-agent for the live-debugging setup. They are committed, so they work
on a fresh clone with no install step. Refresh them with:
npx skills@latest updateAs a plugin. template/.claude/settings.json registers the adora-skills
marketplace and enables the adora plugin, so opening a generated app in Claude
Code prompts you to trust and install the full library. It then resolves as
/adora:<skill-name> β write-tests, verify, commit-changes, gitmoji,
unistyles, truesheet-usage, domain-model, grill-plan, ticket-shaping,
implement-ticket, ios-widget, bootsplash, xcode-cloud. By hand:
/plugin marketplace add ltatarev/skills
/plugin install adora@adora-skills
/plugin marketplace update adora-skillsOn a harness other than Claude Code, install the same library with the
skills.sh picker β see template/.agents/README.md:
npx skills@latest add ltatarev/skillsMIT Β© ltatarev
