Building a Production-Ready React Native App

Building a Production-Ready React Native App

Written by
Written by

Jaydeep A.

Post Date
Post Date

Oct 08, 2025

shares

1_VWhGazdbBQz5hixUzpTr7g

TL;DR (quick overview)

1. Before you write any code : a pre-coding blueprint

Why this matters: engineering time is precious. Clear requirements + targeted questions reduce wrong assumptions, rework, and scope creep. Good pre-coding saves implementation, QA, and release cycles.

What to do?

Why ask lots of questions?

example clarifying Q&A:

1. Q: What if user opens the app without internet?
A: Show cached data if available, else display offline message with retry option. Sync when connection restores.
Why: defines offline behavior & storage needs.

2. Q: When user selects image from gallery, should I use image cropping or use as-is?
A: Implement image cropping for profile pictures with aspect ratio 1:1, but allow original for other images.
Why: clarifies UX expectations and required libraries.

3. Q: Should dark mode follow system preferences or be toggleable inside the app?
A: App must support explicit toggle (light/dark/auto). Default = auto (follow system).
Why: affects theme architecture and persistence.

2. Bootstrapping a bare React Native project (what to install and why)

What problem these CLIs solve:

These tools are like helpers that make React Native development easier. They handle the complicated setup behind the scenes — creating new projects, running your app on Android/iOS, connecting your JavaScript code with native device features, and starting the development server. When you type npx react-native run-android, these CLIs translate that into commands that Android understands.

Why uninstall old global CLI versions before creating a new project:

Think of global CLIs like old recipes — they might not work with new ingredients. If you have an old version installed globally, it could create projects with outdated structure or cause strange errors. Using npx ensures you always get the latest, most compatible version for each new project.

Helpful commands

# List globally installed packages
npm list -g --depth=0
yarn global list

# Check for specific package
npm list -g react-native-cli
yarn global list | grep react-native-cli

# Remove global CLI to avoid conflicts
npm uninstall -g react-native-cli @react-native-community/cli
yarn global remove react-native-cli @react-native-community/cli
Always use the latest stable React Native — why: Newer versions fix bugs, improve security, and make your app faster. It’s like getting a car with better safety features and better gas mileage. Just check the release notes for any breaking changes before updating.

Bootstrapping with npx :

# basic
npx @react-native-community/cli@latest init AwesomeProject
Why npx and not npm or yarn for bootstrapping: npx is like borrowing a tool instead of buying it. You use the exact version you need just once, without cluttering your system. Global installs can cause “it works on my machine” problems because teammates might have different versions.

Install a specific RN version

npx @react-native-community/cli@X.Y.Z init PROJECT_NAME --version X.XX.X

3. Initial must-have setup (what, why, when to avoid, and how)

These items are early, high-impact engineering decisions. Implement them before building screens.

3.1 Choose a package manager : Yarn vs npm

Yarn vs npm choice made simple: Both do the same job — install packages. Yarn was faster initially and better at consistent installs. Modern npm has caught up. Pick what your team knows best. The key is being consistent across your team.

3.2 Production logging : silence console in production

In index.js (entry point) add:
if (!__DEV__) { console.log = () =>null; console.warn = () => null; console.error = () => null; }
Why: Prevents your app from spamming the device logs in production, which can slow down the app and expose sensitive information. Users don’t need to see developer messages.

3.3 Disable font scaling globally

Why disable font scaling: Some users change their device font size for accessibility. This can break your carefully designed layouts by making text too large or overlapping elements. Disabling scaling keeps your design consistent.
When to avoid: If you’re building an app focused on accessibility, you should support font scaling and design your layouts to accommodate larger text.
// Custom Text component that disables font scaling globally export const AppText = (props) => <Text {...props} allowFontScaling={false} />; // Custom TextInput component that disables font scaling globally export const AppTextInput = (props) => <TextInput {...props} allowFontScaling={false} />;

3.4 Theme Mode : Control System Dark Mode

You have two levels of theme control:

Native-level lock : locks the app to a specific mode.


<key>UIUserInterfaceStyle</key>
<string>Light</string> <!-- Light, Dark, or Automatic -->
<item name="android:forceDarkAllowed">false</item> <!-- disable system dark mode -->

JS-level behaviour : respects system preference or user override. Use React Native’s Appearance API:

import { useColorScheme } from "react-native";
const App = () => {   const systemTheme = useColorScheme(); // 'light' | 'dark'   const [theme,setTheme] = React.useState("auto"); // 'light' | 'dark' | 'auto'   const activeTheme = theme === "auto" ? systemTheme : theme;   return (     <View       style={{ backgroundColor: activeTheme === "dark" ? "#000" : "#fff" }}     />   ); };

3.5 Multi-language support with i18next + react-i18next

Use i18next + react-i18next for React Native. VSCode extension i18next-ally helps manage keys and translations.

What i18next-ally solves: shows translation key usages inline, highlights missing keys, and streamlines translators’ workflow in the editor, less guesswork when adding translations.

Example setup:

import enfrom "./en.json"; import hifrom "./hi.json"; import i18n, { InitOptions } from "i18next"; import { initReactI18next } from "react-i18next"; const languages = ["en", "hi"] as const; export type SupportedLanguages = (typeof languages)[number]; const i18nConfig: InitOptions<{ lng: SupportedLanguages }> = {   lng: "en", // default language   fallbackLng: "en", // fallback when a key is missing   resources: {     en: { translation: en },     hi: { translation: hi },   },   interpolation: { escapeValue: false },   react: { useSuspense: false },   compatibilityJSON: "v4", }; i18n.use(initReactI18next).init(i18nConfig); export default i18n;

4. Project Structure & Folder Organization

src/ ├── assets/ │ ├── images/ │ └── fonts/ ├── components/ │ ├── common/ │ │ ├── CustomButton/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ └── CustomText/ │ ├── listItems/ │ │ ├── ChatListItem/ │ │ │ ├── index.tsx │ │ │ └── styles.ts │ │ └── StatusListItem/ │ ├── skeletons/ │ │ ├── ChatListSkeleton/ │ │ └── MessageSkeleton/ │ ├── noData/ │ │ ├── EmptyChats/ │ │ └── NoConnection/ │ └── modals/ │ ├── ImageViewer/ │ └── StatusViewer/ ├── screens/ │ ├── ChatListScreen/ │ │ ├── index.tsx │ │ └── styles.ts │ ├── ChatRoomScreen/ │ ├── StatusScreen/ │ ├── CallsScreen/ │ └── SettingsScreen/ ├── services/ │ ├── api/ │ │ ├── auth/ │ │ ├── chat/ │ │ └── axiosConfig.ts │ └── firebase/ │ ├── auth/ │ ├── firestore/ │ └── storage/ ├── navigation/ │ ├── index.tsx │ ├── AuthNavigator.tsx │ ├── MainNavigator.tsx │ └── types.ts ├── redux/ │ ├── slices/ │ │ ├── authSlice.ts │ │ ├── chatSlice.ts │ │ └── messageSlice.ts │ ├── store.ts │ └── hooks.ts ├── hooks/ │ ├── useAuth.ts │ ├── useChat.ts │ └── useWebSocket.ts ├── config/ │ ├── colors.ts │ ├── fonts.ts │ ├── assetPaths.ts │ └── constants.ts ├── utils/ │ ├── helpers.ts │ ├── validators.ts │ └── formatters.ts └── types/ ├── auth.ts ├── chat.ts └── index.ts

Rationale & best practices

Avoid creating inline subcomponents within a large components file, extract them. Smaller files + single responsibility make review easier and prevent accidental re-render coupling.

Conclusion

This blueprint is intentionally pragmatic and opinionated: clarify requirements first, scaffold projects reproducibly with npx + TypeScript, enforce a small set of initial app rules (log silencing, consistent font scaling policy, theme handling, and i18n), and adopt a clear folder structure that scales as your app grows.