AI-Ready. Production-grade React Native + TypeScript boilerplate with a built-in, provider-agnostic AI service layer. Wire up OpenAI, Anthropic Claude, Google Gemini β or any LLM β in minutes, not days.
Tip
Works great with AI coding assistants. This repo ships with purpose-built guidance files so Cursor, Claude Code, GitHub Copilot, Windsurf, and Gemini CLI all understand the project conventions out of the box:
| File | Used by |
|---|---|
CLAUDE.md |
Claude Code |
AGENTS.md |
Windsurf Β· Codex CLI Β· Gemini CLI |
.cursor/rules/ |
Cursor |
.github/copilot-instructions.md |
GitHub Copilot |
Note
All screens, components, and mock data included in this boilerplate are for demonstration purposes only. They exist to showcase the architecture, theming, navigation, and AI service layer β not to be kept as-is. Feel free to delete any screen, component, or piece of mock data and replace it with your own.
- Showcase
- What's New in v6
- What's Included
- Getting Started
- Path Aliases
- AI Service Layer
- Theme System
- Navigation
- Event Emitter
- Axios Hooks
- Localization
- Utilities
- AI Guidance Files
- Code Quality
- Project Structure
- AI-Ready β provider-agnostic AI service layer for OpenAI, Anthropic, and Gemini
useAIChathook β multi-turn conversations with streaming support, zero boilerplateuseAICompletionhook β single-shot completions for text generation, classification, summarizationRNAIMessagecomponent β role-aware chat bubble with live streaming cursor- AI Chat screen β fully functional demo: provider switcher, API key input, model name input, streaming toggle
- AI Guidance Files β
CLAUDE.md,AGENTS.md,.cursor/rules/,.github/copilot-instructions.mdso every AI coding assistant understands this codebase @hookspath alias β clean imports for all custom hooks
- React Native 0.84 + React 19 β latest stable versions
- New Architecture enabled by default (
newArchEnabled=true, Bridgeless / JSI) - Redesigned Boilerplate Explorer HomeScreen
- Full Montserrat font family bundled (18 weights)
react-native-reanimatedv4 +react-native-worklets- Stricter TypeScript config with typed theme colors and navigation
- Husky v9 pre-commit hooks (
prettier+linton every commit,commitlinton commit message)
| Feature | Description |
|---|---|
| AI Service | Provider-agnostic sendAIMessage() + streamAIMessage() β works with OpenAI, Anthropic, Gemini, or any compatible API |
useAIChat |
Multi-turn conversation hook with history, streaming, error state, and system prompt management |
useAICompletion |
Single-shot completion hook β perfect for generation, summarization, translation, classification |
RNAIMessage |
Role-aware chat bubble component (user / assistant / system) with streaming cursor |
| AI Chat Screen | Live demo screen with provider selector, API key input, model name field, streaming toggle |
| AI Guidance Files | CLAUDE.md Β· AGENTS.md Β· .cursor/rules/ Β· .github/copilot-instructions.md |
| Feature | Library |
|---|---|
| Navigation | @react-navigation/native Β· @react-navigation/stack Β· @react-navigation/bottom-tabs |
| Navigation helpers | react-navigation-helpers β push/pop/navigate without component refs |
| HTTP | axios + axios-hooks |
| Animations | react-native-reanimated v4 + react-native-gesture-handler |
| Icons | react-native-vector-icons + react-native-dynamic-vector-icons |
| Localization | i18next + react-i18next |
| Safe Area | react-native-safe-area-context |
| Splash Screen | react-native-splash-screen |
- Strict TypeScript β extended theme types, typed palette, path aliases
- Path aliases (
@screens,@services,@hooks,@fonts,@theme, β¦) - TextWrapper β typed
h1βh6,bold,italicprops, global font swap in one file - EventEmitter singleton β pub/sub across screens without prop drilling
- Montserrat font family (18 weights) bundled
- ESLint + Prettier with auto import sorting
- Husky pre-commit: lint, format, and commitlint run automatically
git clone https://github.com/kuraydev/react-native-typescript-boilerplate.git my-app
cd my-appnpm installcd ios && pod install && cd ..Create android/local.properties:
# macOS / Linux
sdk.dir=/Users/<your-username>/Library/Android/sdk
# Windows
sdk.dir=C:\\Users\\<your-username>\\AppData\\Local\\Android\\Sdk
# iOS
npm run ios
# Android
npm run android| Command | Description |
|---|---|
npm start |
Start Metro bundler |
npm run start:fresh |
Start Metro with cache reset β use this after adding path aliases |
npm run ios |
Run on iOS simulator |
npm run android |
Run on Android emulator |
npm run lint |
ESLint |
npm run prettier |
Prettier β auto-format all files in src/ |
npm test |
Jest |
npm run prepare |
Initialize Husky hooks (runs automatically after npm install) |
npm run clean:showcase |
Remove showcase/demo content and replace screens with minimal stubs |
The included screens (Home, Search, Notifications, Settings) are demo UIs that showcase the architecture. Once you've explored the boilerplate, run:
npm run clean:showcaseThis will:
- Delete
src/screens/home/mock/(FeatureCards, UtilityItems, StackItems) - Delete
src/screens/home/components/(CardItem) - Replace each showcase screen with a minimal, compilable stub
- Leave AIChatScreen, all shared components, services, theme, and navigation wiring untouched
npx react-native-rename <YourAppName>For a custom Android bundle identifier:
npx react-native-rename <YourAppName> -b com.yourcompany.appnameFor iOS, change the bundle identifier in Xcode.
All aliases are defined in babel.config.js and tsconfig.json. Always prefer aliases over relative imports.
| Alias | Resolves to |
|---|---|
@screens/* |
src/screens/* |
@services/* |
src/services/* |
@hooks |
src/hooks/index |
@shared-components |
src/shared/components |
@shared-constants |
src/shared/constants |
@fonts |
src/shared/theme/fonts |
@font-size |
src/shared/theme/font-size |
@theme/* |
src/shared/theme/* |
@colors |
src/shared/theme/colors |
@models |
src/services/models |
@utils |
src/utils |
@assets |
src/assets |
@event-emitter |
src/services/event-emitter |
@api |
src/services/api/index (stub) |
@local-storage |
src/services/local-storage (stub) |
Example:
// Instead of: ../../../../shared/components/text-wrapper/TextWrapper
import Text from "@shared-components/text-wrapper/TextWrapper";
// Instead of: ../../hooks/useAIChat
import { useAIChat } from "@hooks";After adding a new alias to both
babel.config.jsandtsconfig.json, runnpm run start:freshto reset Metro's cache.
The AI layer is provider-agnostic β the same API, types, and hooks work regardless of whether you're using OpenAI, Anthropic, Gemini, or any other LLM provider. Model names are never hardcoded; you supply whatever model string your API key supports.
interface AIConfig {
provider: "openai" | "anthropic" | "gemini";
apiKey: string;
model?: string; // you supply the model β no defaults enforced
temperature?: number; // defaults to 0.7
maxTokens?: number; // defaults to 1024
systemPrompt?: string;
baseURL?: string; // override for proxies or local LLMs (e.g. Ollama)
}
interface AIMessage {
id: string;
role: "user" | "assistant" | "system";
content: string;
timestamp: number;
}import { useAIChat } from "@hooks";
const {
messages, // AIMessage[] β full conversation history
isLoading, // true while awaiting a full response
isStreaming, // true while tokens are arriving
error, // Error | null
sendMessage, // (content: string) => Promise<void> β full response
streamMessage, // (content: string) => Promise<void> β live tokens
clearMessages,
setSystemPrompt,
} = useAIChat({
config: {
provider: "openai", // or "anthropic" or "gemini"
apiKey: userApiKey,
model: "your-model", // you decide β e.g. "gpt-4o-mini"
},
});
// Full response β UI updates once reply is complete
await sendMessage("Explain React hooks in one paragraph");
// Streaming β the last assistant message updates token by token
await streamMessage("Write a React Native FlatList example");
// Inject a system instruction at any time
setSystemPrompt("You are a concise senior React Native engineer.");import { useAICompletion } from "@hooks";
const { complete, result, isLoading, error, reset } = useAICompletion({
config: { provider: "anthropic", apiKey: key, model: "your-model" },
systemPrompt: "Classify sentiment as: positive, neutral, or negative.",
});
const sentiment = await complete(userReview);import { sendAIMessage, streamAIMessage, buildUserMessage, buildSystemMessage } from "@services/ai";
const messages = [
buildSystemMessage("You are a helpful assistant."),
buildUserMessage("Hello!"),
];
// Full response
const response = await sendAIMessage(messages, config);
console.log(response.message.content);
console.log(response.usage?.totalTokens);
// Streaming
await streamAIMessage(messages, config, {
onToken: (token) => appendToUI(token),
onComplete: (response) => saveToHistory(response),
onError: (err) => showErrorBanner(err.message),
});- Create
src/services/ai/providers/<name>.tsimplementingIAIProvider:
import type { IAIProvider, AIConfig, AIMessage, AIChatResponse, AIStreamCallbacks } from "../types";
export class MyProvider implements IAIProvider {
async sendMessage(messages: AIMessage[], config: AIConfig): Promise<AIChatResponse> {
// call your API, return AIChatResponse
}
async streamMessage(messages: AIMessage[], config: AIConfig, callbacks: AIStreamCallbacks): Promise<void> {
// stream tokens, call callbacks.onToken / onComplete / onError
}
}- Register in
src/services/ai/AIService.ts:
case "<name>":
return new MyProvider();- Extend the union type in
src/services/ai/types.ts:
export type AIProvider = "openai" | "anthropic" | "gemini" | "<name>";- Add metadata:
export const AI_PROVIDER_LABELS: Record<AIProvider, string> = {
// ...existing
"<name>": "My Provider",
};The theme automatically follows the system dark/light mode via useColorScheme.
import { useTheme } from "@react-navigation/native";
const MyComponent = () => {
const { colors } = useTheme();
return <View style={{ backgroundColor: colors.background }} />;
};// MyComponent.style.ts
import { StyleSheet } from "react-native";
import type { ExtendedTheme } from "@react-navigation/native";
const createStyles = (theme: ExtendedTheme) => {
const { colors } = theme;
return StyleSheet.create({
container: { backgroundColor: colors.card, borderColor: colors.borderColor },
});
};
export default createStyles;
// MyComponent.tsx
const styles = useMemo(() => createStyles(theme), [theme]);| Token | Light | Dark |
|---|---|---|
primary |
#4A6CF7 |
#4A6CF7 |
secondary |
#f97316 |
#f97316 |
background |
#f4f6fb |
#0e1117 |
text |
#1e2533 |
#e8edf5 |
placeholder |
#95a0b4 |
#6b7894 |
borderColor |
#e6eaf2 |
#2c313d |
danger |
rgb(208,2,27) |
rgb(208,2,27) |
import Text from "@shared-components/text-wrapper/TextWrapper";
import fonts from "@fonts";
<Text h1 bold color={colors.text}>Title</Text>
<Text h4 color={colors.placeholder}>Subtitle</Text>
<Text fontFamily={fonts.montserrat.lightItalic}>Custom weight</Text>Stack wraps a Bottom Tab navigator. All screen name strings live in SCREENS (@shared-constants) β never use raw strings.
export const SCREENS = {
ROOT: "Root",
HOME: "Home",
SEARCH: "Search",
NOTIFICATION: "Notification",
SETTINGS: "Settings",
DETAIL: "Detail",
AI_CHAT: "AIChat",
};import * as NavigationService from "react-navigation-helpers";
import { SCREENS } from "@shared-constants";
NavigationService.push(SCREENS.DETAIL);
NavigationService.navigate(SCREENS.AI_CHAT);
NavigationService.pop();- Add key to
SCREENSinsrc/shared/constants/index.ts - Create
src/screens/<name>/<Name>Screen.tsx+<Name>Screen.style.ts - Register in
src/navigation/index.tsxas<Tab.Screen>or<Stack.Screen> - Add icon case in
renderTabIconif it's a tab
A singleton EventEmitter at @event-emitter. Broadcast events between screens without prop drilling.
import EventEmitter from "@event-emitter";
// Emit
EventEmitter.emit("USER_LOGGED_IN", { userId: "abc123" });
// Listen (add on mount, remove on unmount)
useEffect(() => {
const handler = (data: { userId: string }) => console.log(data.userId);
EventEmitter.on("USER_LOGGED_IN", handler);
return () => EventEmitter.off("USER_LOGGED_IN", handler);
}, []);Declarative HTTP with built-in loading and error states.
import useAxios from "axios-hooks";
// GET
const [{ data, loading, error }, refetch] = useAxios("https://api.example.com/users");
// POST (manual)
const [{ loading }, executePost] = useAxios(
{ url: "https://api.example.com/users", method: "POST" },
{ manual: true },
);
await executePost({ data: { name: "John" } });String tables in src/shared/localization/index.ts via i18next.
// Add translations
const resources = {
en: { translation: { greeting: "Hello!", logout: "Logout" } },
tr: { translation: { greeting: "Merhaba!", logout: "ΓΔ±kΔ±Ε" } },
};
// Use in components
import { useTranslation } from "react-i18next";
const { t } = useTranslation();
<Text>{t("greeting")}</Text>
// Switch locale
import i18n from "i18next";
i18n.changeLanguage("tr");import { capitalizeFirstLetter, generateRandomNumber } from "@utils";
capitalizeFirstLetter("hello"); // "Hello"
generateRandomNumber(1, 100); // e.g. 42This boilerplate ships with a complete set of guidance files so every AI coding assistant understands the project conventions out of the box β and can help developers extend it correctly.
| File | Read by | Content |
|---|---|---|
CLAUDE.md |
Claude Code | Full project reference: architecture, aliases, AI service docs, conventions, what to avoid |
AGENTS.md |
Windsurf Β· Codex CLI Β· Gemini CLI | Concise snapshot: layout, rules, extension guide |
Cursor reads these automatically when you're working inside the repo.
| Rule file | Content |
|---|---|
project-conventions.mdc |
File naming, aliases, color rules, styles pattern, safe area, touchables |
ai-service.mdc |
AI service architecture, hook usage, adding providers, streaming pattern |
navigation.mdc |
SCREENS constant, adding tabs/stack screens, imperative navigation |
components.mdc |
Creating shared components, TextWrapper/RNButton/RNInput usage, barrel exports |
typescript.mdc |
Strict flags, I-prefix interfaces, export type, exhaustive switch, any policy |
| File | Read by | Content |
|---|---|---|
copilot-instructions.md |
GitHub Copilot | Workspace-level inline suggestion rules |
These files are designed to be extended. As your project grows, update them to reflect new conventions, new services, or new architectural decisions β every AI tool in your team's workflow will stay aligned automatically.
# Lint check
npm run lint
# Auto-format all files in src/
npm run prettierConfig files: .eslintrc.js, .prettierrc, .eslintignore, .prettierignore
Husky runs automatically on every commit. No manual setup needed β npm install triggers prepare which initializes the hooks.
On every git commit:
npm run prettierβ auto-formats all staged source filesnpm run lintβ ESLint must pass with no errors
On the commit message:
3. commitlint β validates the message follows Conventional Commits
Commits must follow Conventional Commits:
feat: add user profile screen
fix: resolve dark mode flicker
chore: upgrade react-navigation to v7
docs: update README
refactor: extract AI provider logic
perf: memoize createStyles calls
test: add useAIChat unit tests
Allowed types: feat Β· fix Β· chore Β· docs Β· style Β· refactor Β· perf Β· test Β· ci Β· revert
Config file: .commitlintrc.json
src/
βββ assets/
β βββ fonts/
β β βββ Montserrat/ # 18 font weights
β βββ splash/
βββ hooks/ # Custom React hooks
β βββ useAIChat.ts # Multi-turn AI conversation hook
β βββ useAICompletion.ts # Single-shot AI completion hook
β βββ index.ts
βββ navigation/
β βββ index.tsx # Stack + Bottom Tab navigator
βββ screens/
β βββ ai-chat/ # AI Chat demo screen
β β βββ AIChatScreen.tsx
β β βββ AIChatScreen.style.ts
β βββ home/
β β βββ HomeScreen.tsx
β β βββ HomeScreen.style.ts
β βββ detail/
β βββ notification/
β βββ search/
β βββ settings/
βββ services/
β βββ ai/ # Provider-agnostic AI service layer
β β βββ providers/
β β β βββ openai.ts # OpenAI Chat Completions
β β β βββ anthropic.ts # Anthropic Messages
β β β βββ gemini.ts # Google Gemini
β β βββ AIService.ts # sendAIMessage, streamAIMessage
β β βββ types.ts # AIMessage, AIConfig, AIChatResponseβ¦
β β βββ index.ts
β βββ event-emitter/
β β βββ index.ts # EventEmitter singleton
β βββ models/
β βββ index.ts # Shared TypeScript interfaces
βββ shared/
β βββ components/
β β βββ ai-message/ # RNAIMessage β chat bubble component
β β βββ badge/RNBadge.tsx
β β βββ button/RNButton.tsx
β β βββ divider/RNDivider.tsx
β β βββ empty-state/RNEmptyState.tsx
β β βββ input/RNInput.tsx
β β βββ loading-indicator/RNLoadingIndicator.tsx
β β βββ text-wrapper/TextWrapper.tsx
β β βββ index.ts # Barrel export
β βββ constants/
β β βββ index.ts # SCREENS enum
β βββ localization/
β β βββ index.ts # i18next (en + tr-TR)
β βββ theme/
β βββ colors.ts
β βββ font-size.ts
β βββ fonts.ts # Montserrat font map
β βββ themes.ts # LightTheme / DarkTheme + palette
βββ utils/
βββ index.ts
Kuray Β· kuraydev.io@gmail.com
MIT β see LICENSE for details.



