On this page
Every React Native job description asks for JavaScript, TypeScript, React, and state management. Every candidate claims to have them. And none of these tell you whether the developer can actually ship a product that works on a $200 Android phone, survives an iOS update cycle, and doesn't need a rewrite six months after launch.
We've vetted hundreds of React Native developers at hirereactnativedevs.com. The pattern is consistent: developers who pass the basics but fail in production are missing the same set of skills. Not obscure skills but skills that are hard to name on a job description and harder to test for in a 45-minute interview but obvious the moment you see someone working on a real codebase.
In this guide, we go beyond surface-level skill lists and focus on what actually important in production React Native work. If you're writing a job description, structuring an interview, or evaluating a developer you've already hired, this is the checklist that you need after you've confirmed the fundamentals.
The Basics (Confirm These, Then Move On)
Before testing for advanced skills, verify the foundation exists. These should take five minutes to confirm, not five interview rounds.
| Skill | What "Confirmed" Looks Like |
|---|---|
| JavaScript / TypeScript | Writes TypeScript in strict mode. Understands generics, union types, async/await patterns. Doesn't use any as a crutch |
| React fundamentals | Functional components, hooks (useState, useEffect, useMemo, useCallback, useRef), component composition, controlled vs uncontrolled inputs |
| React Navigation | Has implemented stack, tab, and drawer navigators. Understands deep linking configuration. Can pass params between screens |
| State management | Can explain when to use local state (useState) vs global state (Zustand, Redux Toolkit, Context API). Understands why putting everything in Redux is an anti-pattern in 2026 |
| REST/GraphQL API integration | Has fetched data from APIs, handled loading and error states, understands HTTP methods, headers, and authentication tokens |
| Git workflow | Branching strategies, pull request process, merge conflict resolution. Uses GitHub or GitLab in a team environment |
If a candidate cannot prove these then they are not ready for a React Native role at any level. But that doesn’t tell you if they’re able to build something that can withstand contact with real users on real devices.
One subtle basic check to add: ask how layout works in React Native vs web CSS or native Android XML. React Native employs flexbox for layout, comparable to CSS flexbox but with different defaults (flex direction defaults to column and align content defaults to flex-start). If a web React developer assumes that flexbox works the same everywhere, their layouts will break on mobile. A developer coming from Android who understands how flexbox maps to LinearLayout with gravity properties has a useful mental model. This is no trivial point. It comes down to whether the developer has actually done layouts on mobile and dealt with the differences or just read about it.
The skills below are what separate a developer who passes this baseline from one who can own a production app.
Skill 1: New Architecture Fluency (JSI, Turbo Modules, Fabric)
React Native 0.76 made the New Architecture the default. Version 0.82 permanently disabled the old bridge. Every new project in 2026 runs on JSI, Turbo Modules, and Fabric. A developer who doesn't understand this layer is working with a mental model of React Native that no longer exists.
What fluency looks like in practice:
// A developer who understands Turbo Modules can write a Codegen spec
import type { TurboModule } from 'react-native';
import { TurboModuleRegistry } from 'react-native';
export interface Spec extends TurboModule {
getDeviceLocale(): string; // synchronous via JSI - not possible on old bridge
fetchUserData(userId: string): Promise<Object>;
}
export default TurboModuleRegistry.getEnforcing<Spec>('DeviceInfo');
A developer who can write this spec, implement the native side in Swift or Kotlin, and debug the Codegen output is operating at the New Architecture layer. A developer who has only called pre-built modules from JavaScript is operating above it. Both are valid, but they're different roles at different price points.
Why this matters for hiring: New Architecture specialists command $145,000-$185,000 in the US, a 20-30% premium over JS-layer developers at $100,000-$128,000. The 2024 Stack Overflow Developer Survey shows React Native used by 9.14% of professional developers, but the fraction who have shipped a production Turbo Module is dramatically smaller. The premium is driven by scarcity.
How to test: "Walk me through the difference between a Native Module and a Turbo Module, and where JSI fits." About a third of senior candidates can't answer at all. For a deep dive, see our post on React Native's New Architecture and what it means when hiring.
Skill 2: Performance Profiling and Optimization
This is the skill with the biggest gap between claim and reality. Every mid-level developer says they “optimize performance.” In practice, that usually means adding React.memo to a few components after reading a blog post. Performance profiling is a diagnostic discipline that needs tools, methodology, and the ability to distinguish between symptoms and root causes.
The difference matters because React Native performance issues have two completely different sources, and the fix for one is useless for the other. When the JavaScript thread is dropping frames, the problem is in your app's logic: excessive re-renders, expensive computations, unoptimized data processing. When the UI thread is dropping frames, the problem is in native rendering: complex view hierarchies, overdraw, expensive shadow calculations. A developer who can't distinguish between these two will spend days applying JS-thread fixes to a UI-thread problem and wondering why nothing improves.
Performance profiling in 2026 means working with Hermes CPU profiler, Flipper's performance monitor, React DevTools profiler, and understanding which thread is the bottleneck:
JS frames dropping → Problem is in JavaScript
→ Excessive re-renders, expensive computations, unoptimized data processing
→ Fix with React.memo, useMemo, useCallback, code splitting
UI frames dropping → Problem is in native rendering
→ Complex view hierarchies, overdraw, expensive shadow/elevation calculations
→ Fix with simpler view structure, FlashList instead of FlatList, Reanimated worklets
A developer who can run this diagnostic workflow finds problems in minutes that a developer without profiling skills spends days guessing about.
Here is what a real performance fix looks like. This is one of the most common performance problems in React Native apps, and most developers get it wrong:
// BAD: This renders every item in the list every time anything changes
// The inline function creates a new reference on each render,
// defeating React's memoization
<FlatList
data={items}
renderItem={({ item }) => (
<View style={{ padding: 16 }}>
<Text>{item.title}</Text>
<TouchableOpacity onPress={() => handlePress(item.id)}>
<Text>View Details</Text>
</TouchableOpacity>
</View>
)}
/>
// GOOD: Memoized list item + FlashList for recycling
const ListItem = React.memo(({ item, onPress }) => (
<View style={{ padding: 16 }}>
<Text>{item.title}</Text>
<TouchableOpacity onPress={() => onPress(item.id)}>
<Text>View Details</Text>
</TouchableOpacity>
</View>
));
<FlashList
data={items}
renderItem={({ item }) => (
<ListItem item={item} onPress={handlePress} />
)}
estimatedItemSize={72}
/>
The difference between these two versions is invisible on a list of 20 items. On a list of 500 items on a mid-range Android phone, the first version drops frames visibly during scroll. The second version stays at 60fps because FlashList recycles views (like Android's RecyclerView) and React.memo prevents re-renders of items that haven't changed. A developer who writes the first version and a developer who writes the second version both "know React Native." Only one of them has shipped a list that users actually scroll through.
Why this matters for hiring: The 2024 Stack Overflow survey shows that 52.9% of professional developers prioritize code quality, but performance profiling is a subset of that group. Most developers write code that works. Fewer write code that's fast. On mobile, the difference is visible to users in scroll jank, slow startup, and battery drain.
How to test: "Your FlatList with 500+ items is janky on Android. Walk me through how you'd diagnose and fix it." The depth of the answer maps directly to seniority. See our interview questions guide for junior, mid, and senior answer benchmarks.
Skill 3: Animation Engineering with Reanimated 3
Users judge app quality by how it feels, and feel is determined by animation. Smooth, responsive interactions - gesture-driven drawers, parallax scrolling, spring-physics button feedback - are what separate a React Native app that feels native from one that feels like a wrapped website.
In 2026, production animation work means Reanimated 3. The critical concept: shared values are not React state. They update the UI thread directly via worklets (JavaScript functions compiled to run outside the main JS thread), so animations run at 60fps even when the JS thread is busy processing data.
// Reanimated 3: animation runs on UI thread, never blocks JS thread
import Animated, {
useSharedValue,
withSpring,
useAnimatedStyle,
} from 'react-native-reanimated';
const translateX = useSharedValue(0);
// Gesture drives the animation directly on UI thread
const onGestureEvent = useAnimatedGestureHandler({
onActive: (event) => {
translateX.value = event.translationX; // No bridge, no JS thread involvement
},
onEnd: () => {
translateX.value = withSpring(0); // Spring physics on UI thread
},
});
A developer who writes Animated.timing from the old API for everything is producing animations that will stutter under load. A developer who naturally reaches for Reanimated shared values and worklets is building interactions that feel native.
How to test: “Explain the difference between Animated API, LayoutAnimation, and Reanimated. When would you use either?" The strong answer is about what thread each runs on and why it matters.
Skill 4: Native Module Development (Swift/Kotlin)
React Native's npm ecosystem covers most common needs. But the moment your app requires a hardware integration that no existing package handles, a specific Bluetooth protocol, a custom camera pipeline, NFC tag writing, or biometric auth beyond the standard APIs, you need a developer who can write native code.
That means Swift for iOS and Kotlin for Android. Beyond reading native code (which most mid-level developers can do), you should be able to write Turbo Module implementations, debug native crash logs in Xcode and Android Studio, configure Podfiles and Gradle build files, and understand platform-specific lifecycle events.
Interesting trend in hiring in 2026. Some of the best React Native developers had native Android or iOS experiences. They were skeptics at the beginning, built a project with React Native and found the cross-platform productivity gains were real. These developers bring something that pure JavaScript developers don't have, an intuitive understanding of how the native layer works underneath React Native. They know what componentDidMount maps to in the Android lifecycle. They understand why flexbox in React Native behaves slightly differently than CSS flexbox on the web. They can read a native crash log and know immediately whether the problem is in JavaScript or in the platform layer. When you find a developer with 3+ years of native mobile experience who then spent 2+ years in React Native, that combination is more valuable than either skill set alone.
Why this matters for hiring: Native module skills command a 15-20% salary premium because they bridge two separate disciplines. A developer who writes both TypeScript and Swift is rarer than one who writes only TypeScript. If your app stays entirely within Expo's managed ecosystem, you don't need this. If your app touches hardware or requires custom platform behavior, you do. Clarify this in the job description. See our post on Expo vs. bare React Native for when each workflow requires native skills.
Skill 5: Testing Strategy (Not Just Writing Tests)
The difference is between a developer who writes tests and a developer with a testing strategy. The first adds Jest tests if asked to. The second is a testing approach that finds bugs before users see them and doesn’t slow the team down with flaky tests that waste everyone’s time.
A production testing strategy in 2026 looks like this:
| Level | Tool | What It Catches | Run Frequency |
|---|---|---|---|
| Unit tests | Jest | Business logic bugs, utility function errors | Every commit |
| Component tests | React Native Testing Library | UI behavior regressions (tap button → correct text appears) | Every PR |
| E2E tests | Detox or Maestro | Critical user flows (signup, checkout, payment) | Before every release |
| Device testing | Physical devices + CI matrix | Platform-specific bugs, performance issues | Weekly + before release |
The developer you want understands the tradeoffs between these levels. Unit tests are fast and cheap but don't catch integration bugs. E2E tests catch real user-facing bugs but are slow and flaky. The sweet spot for most React Native apps is heavy investment in component tests with React Native Testing Library - fast enough to run on every commit, high-level enough to catch real regressions.
This is how a good component test actually looks. Not a test checking implementation details but testing behavior as experienced by a user:
// Testing a login form from the user's perspective
import { render, fireEvent, waitFor } from '@testing-library/react-native';
import LoginForm from '../LoginForm';
test('shows error when submitting empty email', async () => {
const { getByText, getByPlaceholderText } = render(<LoginForm />);
// User taps the login button without entering an email
fireEvent.press(getByText('Log In'));
// User should see a clear error message
await waitFor(() => {
expect(getByText('Email is required')).toBeTruthy();
});
});
test('calls onSubmit with email and password when form is valid', async () => {
const mockSubmit = jest.fn();
const { getByText, getByPlaceholderText } = render(
<LoginForm onSubmit={mockSubmit} />
);
// User fills in the form
fireEvent.changeText(getByPlaceholderText('Email'), '[email protected]');
fireEvent.changeText(getByPlaceholderText('Password'), 'securepass123');
fireEvent.press(getByText('Log In'));
// The form should submit with the correct data
await waitFor(() => {
expect(mockSubmit).toHaveBeenCalledWith({
email: '[email protected]',
password: 'securepass123',
});
});
});
Notice what this test does not do. It doesn't check whether a specific state variable was set. It doesn't assert that a particular function was called internally. It tests what the user sees and does: tap a button, see an error, fill a form, submit it. If someone refactors the internal state management of this component, the test still passes as long as the user experience is the same. That's what makes it valuable. Tests that break every time you refactor are worse than no tests at all because they slow the team down without catching real bugs.
How to test: "Walk me through your testing strategy for a React Native app." Then: "Show me a test you've written recently." A developer who writes tests regularly can pull one up immediately. One who doesn't will stall.
Skill 6: CI/CD and Deployment Automation
Building a React Native app and shipping it to users are separate skill sets. The deployment pipeline - cloud builds, code signing, app store submission, over-the-air updates, environment management - is where many developers hit a wall because it's not something tutorials teach.
In 2026, the production standard is:
# EAS Build configuration (eas.json)
{
"build": {
"development": {
"distribution": "internal",
"ios": { "simulator": true }
},
"staging": {
"distribution": "internal",
"channel": "staging"
},
"production": {
"autoIncrement": true,
"channel": "production"
}
}
}
A developer who can configure multi-environment builds (dev/staging/production), manage iOS certificates and Android keystores, automate version bumping, run tests in CI before every build, and push OTA updates through EAS Update without a full store release is significantly more valuable than one who builds locally and submits manually.
How to test: "Walk me through how you'd set up CI/CD for a React Native app that deploys to both app stores." A strong answer includes environment separation, automated testing before builds, and an OTA update strategy for JavaScript-only changes.
Skill 7: Security Awareness
Mobile security is different from web security, and most React Native developers coming from web backgrounds don't know what they don't know. The JavaScript bundle in a React Native app can be extracted from the APK or IPA and read. AsyncStorage is unencrypted. The clipboard is accessible to other apps. iOS takes a screenshot when backgrounding that can expose sensitive data.
A developer with security awareness stores auth tokens in the device keychain (not AsyncStorage), implements certificate pinning, never puts API keys in the JavaScript bundle, and understands the difference between device-level encryption and app-level encryption.
Here is the difference between a developer who understands mobile security and one who doesn't:
// WRONG: AsyncStorage is unencrypted. Anyone with device access can read this.
// This is the most common security mistake in React Native apps.
import AsyncStorage from '@react-native-async-storage/async-storage';
await AsyncStorage.setItem('authToken', token);
await AsyncStorage.setItem('refreshToken', refreshToken);
// These tokens are stored in plain text on the device filesystem
// RIGHT: Use the device keychain, which is encrypted by the OS
import * as Keychain from 'react-native-keychain';
// Store credentials in iOS Keychain / Android Keystore
await Keychain.setGenericPassword('authToken', token, {
accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED,
// Token is only accessible when the device is unlocked
});
// Retrieve securely
const credentials = await Keychain.getGenericPassword();
if (credentials) {
const token = credentials.password;
// Use token for API requests
}
// Clear on logout
await Keychain.resetGenericPassword();
The difference between these two approaches is invisible during development and testing. Both store and retrieve tokens correctly. The difference becomes catastrophic when a user's device is compromised, when your app is audited for compliance, or when a security researcher decompiles your APK and publishes a blog post about how your app stores auth tokens in plaintext. That blog post has ended companies.
Why this matters for hiring: For content apps and simple utilities, basic security practices are sufficient. For fintech, healthcare, enterprise, or any app handling personal data, security awareness is non-negotiable. If your app processes payments, stores health records, or handles authentication tokens, you need a developer who thinks about security proactively, not one who learns about OWASP Mobile Top 10 after the first penetration test fails. See our fintech hiring guide for compliance-specific requirements.
Skill 8: Cross-Platform Debugging and Device Testing
Every experienced React Native developer has a story about the bug that only appeared on a specific Android device and took three days to find. The simulator doesn't reproduce manufacturer-specific font scaling overrides. It doesn't show you how your app behaves when Samsung's OneUI interferes with your navigation gestures. It doesn't reveal the memory pressure that crashes your app on a device with 3GB of RAM when your M3 MacBook has 36GB.
Cross-platform debugging is a skill you can only develop by shipping real apps to real users on real devices. It means owning at least one mid-range Android test device (where the real performance issues surface, not on the latest Pixel), understanding how iOS and Android handle permissions differently, reading native crash logs from both Xcode and Logcat when the error isn't a JavaScript exception, and knowing when to use Platform.OS for conditional logic versus .ios.js and .android.js file extensions for fundamentally different implementations.
The developers who are strongest at this have a mental catalog of platform-specific gotchas they've encountered personally: Android 12's PendingIntent mutability flag that broke half the push notification libraries, iOS 17's new privacy permissions that changed how apps access the photo library, Samsung devices that render shadows differently than stock Android. This knowledge can't be learned from documentation. It comes from debugging production apps across a device matrix and remembering what broke.
How to test: "Describe how you would debug a crash that only happens on physical Android devices running Android 12, but works fine on simulators and iOS." A strong answer starts with crash logs from Sentry or Crashlytics, checks for Android 12-specific permission changes, and connects a physical device via USB for adb logcat. A weak answer says "I'd check the console."
Skill 9: Product Thinking
This is the skill that isn’t on any technical skills checklist but is on every successful project we’ve seen.
A product minded developer will write error handling code, that asks “What does the user see when this fails?” They question a feature that adds 3 weeks of complexity when a simpler one delivers 80% of the business value. They see a design decision create a bad experience on smaller screens before QA finds it. They understand that code is a means to an end, not an illustration of engineering sophistication.
Why is this important for React Native specifically? Mobile apps are more personal to the user than any other software. A web app can get away with a slow page and a loading spinner. A mobile app that stutters, that shows a white screen for 2 seconds when you navigate, or that takes 3 taps to do something that should take 1 will lose users who never come back. These are stakes a product-thinking developer knows and understands. If you’re only thinking about the code then a janky transition is a valid technical tradeoff, but it’s very much a user retention problem.
You can’t assess product thinking via a coding challenge. You test for it by listening to the questions a candidate asks during the interview . On the technical side, do they ask "What does the user see when this fails?" or just "What's the error format?" In the architecture discussion do they ask "How many concurrent users are we expecting ? " or just " What database should I use ? " When you describe a feature, do they ask why it matters to the user or do they start talking about implementation?
The developers who build the best apps are the ones who understand why they're building them.
The Skills Matrix: What to Require at Each Level
Not every role needs every skill. Here's how to weight them:
| Skill | Junior | Mid-Level | Senior |
|---|---|---|---|
| New Architecture (JSI/Fabric/Turbo Modules) | Not expected | Awareness, can explain concepts | Hands-on production experience |
| Performance profiling | Basic (console.log debugging) | Uses Flipper, React DevTools | Hermes profiler, JS vs UI thread diagnosis |
| Reanimated 3 | Basic Animated API | Shared values, worklets, gesture handler | Complex gesture-driven interactions, 60fps guarantee |
| Native modules (Swift/Kotlin) | Not expected | Reads native code, basic Xcode/AS | Writes custom Turbo Modules from scratch |
| Testing strategy | Writes basic Jest tests when asked | Component tests with RNTL, understands tradeoffs | Designs testing pyramid, sets up CI integration |
| CI/CD and deployment | Has submitted to one store | Manages certificates, releases independently | Multi-env builds, OTA updates, automated pipelines |
| Security | Awareness of basics | Keychain storage, no secrets in bundle | Certificate pinning, threat modeling, compliance |
| Cross-platform debugging | Tests on simulator | Tests on physical devices, reads basic native logs | Diagnoses platform-specific native crashes |
| Product thinking | Follows specs | Asks clarifying questions about user impact | Shapes product decisions, pushes back on scope |
A mid-level developer should demonstrate at least awareness across all nine skills and hands-on experience in four or five. A senior developer should demonstrate hands-on experience in seven or more with depth in at least three.
What to Do Next
The skills above are what separate developers who build screens from developers who ship products. Use the matrix to write job descriptions that filter for the right level, structure interviews that test for real capability, and evaluate candidates against a concrete framework instead of gut feeling.
For the full hiring process - sourcing, screening, interviewing, and onboarding - see our step-by-step hiring guide. For interview questions that test each of these skills specifically, see our interview questions guide.
At Hire React Native Developers, every developer on our platform has been evaluated against this exact skills framework. They've demonstrated New Architecture fluency, performance profiling ability, and production deployment experience. Vetted senior developer in your team within 5 days, 2-week risk-free trial.
Hire a React Native Developer →