Skip to main content

Improving React Native App Performance on Older Android Devices

· 6 min read
Mobile Developer
Last updated on May 18, 2026

Improving React Native performance on older Android devices

Older Android phones expose every expensive choice in a React Native app: heavy startup work, oversized images, slow lists, chatty network calls, JS-thread animations, and debug-only assumptions. The goal is not to chase one magic setting. The goal is to measure on real hardware, reduce work on the critical path, and ship a release build that keeps memory, CPU, and frame time under control.

Quick Answer

To improve React Native performance on older Android devices, profile a release-like build on a physical low-end phone, keep Hermes enabled, reduce JavaScript startup work, virtualize long lists, use thumbnails instead of full-size images, move expensive animation work off the JS thread, shrink release builds with Android's current optimization tools, and test the same flows before every release.

For broader context, read the React Native performance guide, Android performance measurement docs, and our FlatList optimization guide.


Start With a Device Baseline

Emulators are useful for fast iteration, but older Android performance must be measured on physical hardware. Pick one device that represents the lower end of your supported audience and keep it as a regression device.

Measure these flows:

  • cold start to usable first screen;
  • login and onboarding;
  • opening the main feed;
  • scrolling a long list with images;
  • media upload or playback;
  • maps and location flows;
  • chat or realtime updates;
  • background and foreground resume.

Use Android Studio Profiler for CPU, memory, graphics, and energy behavior. Avoid making conclusions from debug builds because development mode adds overhead that users do not see.

Keep Hermes and Runtime Compatibility in Mind

Hermes is optimized for React Native and is the default JavaScript engine in Expo. It can help startup time and memory usage, especially on lower-end Android devices. In most modern projects, the important work is verifying that Hermes remains enabled and that OTA updates target the correct runtime version after native changes.

For Expo apps, review Expo's Hermes guide before changing JavaScript engine settings. For bare apps, confirm the React Native version and Android build configuration support the engine you ship.


Mega Bundle Sale is ON! Get ALL of our React Native codebases at 90% OFF discount 🔥

Get the Mega Bundle

Reduce Startup Work

Older devices feel slow when too much happens before the first useful screen. Move non-critical work out of startup:

  • lazy load large feature modules;
  • defer analytics setup until after the first screen renders;
  • avoid parsing large local JSON files on launch;
  • avoid eager image preloading for screens the user has not opened;
  • initialize SDKs only when their feature is enabled;
  • keep splash screen work short and deterministic.

Prefer a small authenticated shell that loads the first screen quickly, then hydrate secondary modules in the background.

Optimize Lists Before Rewriting Screens

Feeds, catalogs, chats, restaurant menus, real estate grids, and dating cards often account for most perceived lag.

Use the built-in list tools first:

import { memo, useCallback } from 'react';
import { FlatList, Text, View } from 'react-native';

type Item = {
id: string;
title: string;
};

const Row = memo(function Row({ title }: { title: string }) {
return (
<View style={{ height: 64, justifyContent: 'center' }}>
<Text numberOfLines={1}>{title}</Text>
</View>
);
});

export function OptimizedList({ data }: { data: Item[] }) {
const renderItem = useCallback(({ item }: { item: Item }) => {
return <Row title={item.title} />;
}, []);

return (
<FlatList
data={data}
keyExtractor={item => item.id}
renderItem={renderItem}
initialNumToRender={8}
maxToRenderPerBatch={8}
windowSize={5}
getItemLayout={(_, index) => ({
length: 64,
offset: 64 * index,
index,
})}
/>
);
}

Tune these values on the target device. Smaller windows reduce memory but can show blank areas during fast scrolls. Larger windows feel smoother but retain more rows.

Use Smaller Images and Less Decoding Work

Full-size images in feed rows are one of the fastest ways to make older Android devices stutter.

Use this checklist:

  • request server-side thumbnails for list rows;
  • reserve the original image for detail screens;
  • set explicit image dimensions to avoid layout churn;
  • cache responsibly, but do not preload every image in a long feed;
  • remove images from rows that are not visible or useful;
  • test memory after scrolling deep into the list.

If a screen combines video, image galleries, and infinite scrolling, profile memory as seriously as frame rate.

Keep Animations Off the JS Thread

Animations that depend on JavaScript work can stutter when the app is also fetching data, rendering rows, or handling gestures. Use React Native's native-driven animation options and libraries such as Reanimated when the interaction needs to stay smooth during JS work.

Prioritize:

  • screen transitions;
  • bottom sheets;
  • swipe cards;
  • chat composer movement;
  • map overlays;
  • skeleton loading states.

Avoid running expensive calculations inside gesture callbacks or list row render functions.

Shrink and Optimize Release Builds

Android release builds should use the current Android optimization stack, including R8 and resource shrinking where appropriate. Keep custom keep rules minimal and test every feature that depends on reflection, serialization, native modules, or SDK callbacks.

Use the Android docs for app optimization with R8 and confirm the result with a release build on the target device. Do not assume a smaller APK automatically means smoother runtime performance. Measure startup, memory, and key flows after each change.

Reduce Network and State Churn

Performance problems often look like rendering issues but start in data flow:

  • debounce search and filtering;
  • paginate feeds and catalogs;
  • avoid refetching the same data on every focus event;
  • normalize data so small updates do not re-render the whole screen;
  • cache images and API responses deliberately;
  • show stale data while refreshing where the product allows it.

For API-heavy screens, see React Native REST API integration and debugging network requests.

Release Checklist for Older Android Devices

Before shipping:

  • test a release-like build on a physical low-end Android device;
  • profile startup, list scroll, media, and navigation flows;
  • confirm Hermes is enabled where expected;
  • verify list rows use stable keys and memoized components;
  • test image-heavy screens after long scrolling sessions;
  • check memory after background and foreground resume;
  • run typecheck, app smoke tests, and release build validation;
  • use the Instamobile release checklist.
Looking for a custom mobile application?

Our team of expert mobile developers can help you build a custom mobile app that meets your specific needs.

Get in Touch