React Native Nitro와 TurboModule 정리: New Architecture에서 네이티브 모듈을 선택하는 기준

요약

React Native Nitro와 TurboModule은 둘 다 JavaScript와 네이티브 코드 사이의 병목을 줄이기 위해 등장한 네이티브 모듈 방식이다. 다만 위치가 다르다. TurboModule은 React Native New Architecture의 공식 네이티브 모듈 시스템이고, Nitro Modules는 JSI 위에서 더 객체 지향적이고 빠른 네이티브 바인딩을 제공하려는 서드파티 프레임워크다. 이 글에서는 TurboModule과 Nitro가 각각 무엇인지, 실제 프로젝트에서 어떤 기준으로 선택하면 좋은지, 그리고 도입할 때 자주 막히는 지점을 정리한다.

목차

배경

React Native를 오래 쓰다 보면 언젠가 JavaScript만으로는 처리하기 어려운 영역을 만난다. 카메라 프레임 처리, 암호화, 로컬 데이터베이스, 센서, BLE, 이미지/오디오 처리, 플랫폼 전용 SDK 연동이 대표적이다. 이때 React Native 앱은 JavaScript에서 네이티브 API를 호출해야 한다.

과거의 Legacy Native Module은 JavaScript와 네이티브 사이에 비동기 브리지를 두고 데이터를 직렬화해서 주고받았다. 일반적인 앱 기능에는 충분했지만, 큰 바이너리 데이터나 매우 자주 호출되는 네이티브 함수에는 부담이 컸다. React Native New Architecture는 이 한계를 줄이기 위해 Fabric, TurboModule, Codegen, JSI 같은 기반을 도입했다.

2026년 6월 18일 기준으로 npm의 react-native 최신 버전은 0.86.0이며, React Native 공식 문서는 0.76부터 New Architecture가 기본 활성화되는 흐름을 설명한다. Nitro Modules의 npm 최신 버전은 react-native-nitro-modules@0.35.9로 확인했다. 버전이 빠르게 바뀌는 영역이므로, 실제 도입 전에는 현재 프로젝트의 React Native 버전과 사용하는 라이브러리의 요구사항을 반드시 다시 확인하는 편이 안전하다.

TurboModule이란 무엇인가

TurboModule은 React Native New Architecture에서 네이티브 모듈을 만드는 공식 방식이다. 핵심은 세 가지다.

1. TypeScript 또는 Flow로 네이티브 모듈의 인터페이스를 선언한다. 2. React Native Codegen이 이 선언을 읽고 Android/iOS용 네이티브 인터페이스를 생성한다. 3. 개발자는 생성된 인터페이스를 구현하고, JavaScript에서는 타입이 맞는 API처럼 호출한다.

간단히 말해 TurboModule은 “React Native 코어가 제공하는 타입 기반 네이티브 모듈 시스템”이다. 공식 문서의 예시는 NativeLocalStorage 같은 모듈을 TypeScript spec으로 선언한 뒤 Android에서는 SharedPreferences, iOS에서는 NSUserDefaults로 구현하는 흐름을 보여준다.

// NativeLocalStorage.ts 예시 형태
import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';

export interface Spec extends TurboModule {
  getItem(key: string): string | null;
  setItem(value: string, key: string): void;
  removeItem(key: string): void;
  clear(): void;
}

export default TurboModuleRegistry.getEnforcing<Spec>('NativeLocalStorage');

TurboModule의 장점은 공식 지원이다. React Native 코어의 일부이기 때문에 별도 런타임 프레임워크에 강하게 의존하지 않는다. New Architecture와 함께 가는 방향이 분명하고, 라이브러리 호환성 논의도 대부분 TurboModule/Fabric 기준으로 진행된다.

다만 “공식 방식”이라는 말이 곧 “가장 간단하다”는 뜻은 아니다. Codegen 설정, Android/iOS 빌드 설정, New Architecture 활성화 여부, C++/Objective-C++/Java/Kotlin 경계가 얽히면 초반 진입장벽이 있다. 특히 라이브러리를 배포하는 입장에서는 이전 Legacy Architecture까지 같이 지원할지, New Architecture만 지원할지 결정해야 한다.

Nitro Modules란 무엇인가

Nitro Modules는 Margelo의 Marc Rousavy가 만든 React Native 네이티브 모듈 프레임워크다. 공식 React Native 코어 기능은 아니지만, JSI 기반으로 빠르고 타입 안전한 네이티브 바인딩을 제공하는 것을 목표로 한다.

Nitro의 핵심 개념은 Hybrid Object다. TurboModule이 보통 하나의 모듈을 싱글톤 API처럼 노출하는 반면, Nitro는 JavaScript에서 네이티브 객체를 일반 객체처럼 만들고 메서드와 프로퍼티를 호출하는 모델을 강조한다.

// Math.nitro.ts 예시 형태
import type {HybridObject} from 'react-native-nitro-modules';

export interface Math extends HybridObject<{ios: 'swift'; android: 'kotlin'}> {
  readonly pi: number;
  add(a: number, b: number): number;
}
import {NitroModules} from 'react-native-nitro-modules';
import type {Math} from './specs/Math.nitro';

const math = NitroModules.createHybridObject<Math>('Math');
const result = math.add(5, 3);

Nitro는 nitrogen이라는 코드 생성기를 통해 TypeScript 인터페이스에서 C++, Swift, Kotlin 바인딩을 생성한다. iOS에서는 Swift와 C++ interop을 활용해 Objective-C 경유를 줄이는 방향을 취하고, Android에서는 Kotlin/Java 및 C++ 연동을 지원한다.

Nitro 공식 문서는 단일 네이티브 메서드를 100,000번 호출하는 벤치마크에서 Nitro가 TurboModule보다 빠른 결과를 보였다고 설명한다. 다만 이 수치는 “네이티브 메서드 호출 처리량”을 극단적으로 비교한 결과이고, 실제 앱 성능은 렌더링, 네트워크, 데이터 구조, 디스크 I/O, JS 로직 등 다른 병목에 의해 달라진다. 그래서 Nitro를 선택할 때는 벤치마크 숫자만 보지 말고 “내 앱이 정말 네이티브 호출 경계에서 병목을 겪는가”를 먼저 확인해야 한다.

TurboModule과 Nitro 비교

구분 TurboModule Nitro Modules
위치 React Native 공식 New Architecture 구성 요소 JSI 기반 서드파티 프레임워크
코드 생성 React Native Codegen Nitrogen
API 모델 모듈/함수 중심, 보통 싱글톤처럼 사용 Hybrid Object 중심, 객체와 프로퍼티 모델 강조
iOS 구현 Objective-C/Objective-C++ 기반 예제가 많고 Swift는 별도 브리징 고려 필요 Swift 5.9+와 C++ interop을 적극 활용
Android 구현 Java/Kotlin/C++ 가능 Kotlin/Java/C++ 가능
강점 공식성, 생태계 표준, 장기 호환성 고성능 호출, 객체 모델, 타입 안정성, Swift/Kotlin 친화적 설계
주의점 Codegen과 New Architecture 설정이 까다로울 수 있음 별도 의존성, 최소 요구사항, 빠르게 변하는 API/빌드 이슈 확인 필요

TurboModule은 React Native 프로젝트의 기본 방향과 맞는다. “네이티브 모듈을 만들어야 하는데 공식 방식으로 가고 싶다”면 우선 TurboModule을 검토하는 것이 자연스럽다.

Nitro는 성능과 객체 모델이 중요한 라이브러리에서 매력적이다. 예를 들어 이미지 객체, 프레임 객체, 데이터베이스 핸들, 오디오 버퍼처럼 “네이티브 객체를 JavaScript 쪽에서 계속 들고 다니며 조작하는” 모델에는 Nitro의 Hybrid Object 방식이 잘 맞을 수 있다.

선택 기준

앱 내부에서 가볍게 네이티브 API를 호출한다면 TurboModule부터 본다

앱 안에서 몇 개의 플랫폼 API를 호출하는 정도라면 TurboModule이 일반적으로 더 안전한 기본값이다. React Native 공식 문서와 릴리스 노트의 변화가 TurboModule을 기준으로 설명되고, New Architecture의 일부이기 때문이다.

예를 들어 앱 설정 저장, 간단한 디바이스 정보 조회, 내부 SDK 호출처럼 호출 빈도가 높지 않고 반환 데이터가 단순하다면 TurboModule로 충분한 경우가 많다.

라이브러리를 만들고 고성능 객체 모델이 필요하면 Nitro를 검토한다

반대로 라이브러리 제작자가 네이티브 객체를 JavaScript에 직접 노출하고 싶거나, 매우 많은 네이티브 호출이 성능 병목이 되는 경우에는 Nitro를 검토할 만하다. 특히 Swift/Kotlin으로 현대적인 네이티브 코드를 작성하고 싶은 팀에는 Nitro의 개발 경험이 매력적일 수 있다.

다만 Nitro는 React Native 코어 기능이 아니다. 따라서 팀이 감당해야 할 빌드 환경 요구사항, 버전 호환성, 이슈 대응 비용을 같이 봐야 한다.

Expo Managed Workflow만 보고 있다면 먼저 라이브러리 호환성을 확인한다

Expo 앱에서도 네이티브 모듈이 필요할 수 있지만, Managed Workflow에서는 네이티브 코드 추가 방식이 제한될 수 있다. Expo Dev Client, config plugin, prebuild 여부에 따라 접근이 달라진다. Nitro나 TurboModule 기반 라이브러리를 쓰려면 해당 라이브러리가 Expo 환경을 어떻게 지원하는지 먼저 확인해야 한다.

실제로 헷갈리는 부분과 해결

사례 1. New Architecture를 켰는데 TurboModule이 로드되지 않는다

증상은 보통 이런 형태다.

TurboModuleRegistry.getEnforcing(...): 'NativeSomething' could not be found

이 경우에는 먼저 “JavaScript spec 이름”, “네이티브 모듈 이름”, “Codegen 설정의 name/jsSrcsDir”, “패키지 등록”이 서로 맞는지 확인한다.

{
  "codegenConfig": {
    "name": "NativeLocalStorageSpec",
    "type": "modules",
    "jsSrcsDir": "specs",
    "android": {
      "javaPackageName": "com.nativelocalstorage"
    }
  }
}

여기서 자주 막히는 지점은 spec 파일 위치와 모듈 이름이다. TurboModuleRegistry.getEnforcing&lt;Spec&gt;(&#x27;NativeLocalStorage&#x27;)에서 쓰는 문자열과 네이티브 구현의 NAME이 다르면 런타임에서 모듈을 찾지 못한다. Android/iOS를 각각 클린 빌드해야 생성 코드가 반영되는 경우도 많다.

사례 2. Codegen이 TypeScript 타입을 처리하지 못한다

React Native GitHub 이슈에는 Codegen이 일부 imported type, 복잡한 union, map/null 처리에서 기대와 다르게 동작한다는 사례가 계속 올라온다. 모든 TypeScript 표현이 네이티브 바인딩으로 자연스럽게 변환되는 것은 아니다.

해결의 첫 단계는 spec을 단순하게 만드는 것이다.

// 피하는 편이 안전한 형태: 외부 파일에서 복잡한 타입을 import해서 바로 사용
import type {ExternalComplexType} from './types';

export interface Spec extends TurboModule {
  save(value: ExternalComplexType): void;
}
// 더 안전한 형태: Codegen이 이해하기 쉬운 구조로 spec 경계를 단순화
export type SavePayload = {
  id: string;
  name: string;
  count?: number;
};

export interface Spec extends TurboModule {
  save(value: SavePayload): void;
}

복잡한 객체를 그대로 넘기기보다 네이티브 경계에서 필요한 값만 명확히 정의하면 빌드 오류와 플랫폼별 차이를 줄일 수 있다.

사례 3. Nitro 설치 후 iOS/Android 빌드가 깨진다

Nitro는 최신 JSI, C++, Swift/Kotlin, NDK/Xcode 환경에 기대는 부분이 있다. 공식 문서 기준으로 Nitro는 React Native 0.75 이상, iOS는 Xcode 16.4 이상 및 Swift 5.9 이상, Android는 compileSdkVersion 34 이상과 NDK 27 이상을 요구한다.

먼저 아래를 확인한다.

node -v
npm view react-native version
npm view react-native-nitro-modules version

Android에서는 compileSdkVersion, ndkVersion, CMake/Gradle 로그를 확인하고, iOS에서는 Xcode Report Navigator에서 실제 실패한 컴파일 로그의 마지막 오류를 봐야 한다. “BUILD FAILED”만으로는 원인을 알 수 없다.

특히 Nitro GitHub 이슈를 보면 Swift C++ interop, generated header 충돌, Android NDK/16KB page size 같은 네이티브 빌드 계층 이슈가 등장한다. 이런 문제는 JavaScript 코드만 보고 해결하기 어렵다. 최소 요구사항을 맞춘 뒤에도 깨진다면, 전체 로그 중 실제 error 라인과 사용 중인 React Native/Nitro/Xcode/NDK 버전을 함께 정리해 이슈를 찾아보는 것이 빠르다.

모범 사례

네이티브 경계는 작고 명확하게 만든다

TurboModule이든 Nitro든 JavaScript와 네이티브 사이의 API는 작고 명확해야 한다. JS 객체 전체를 통째로 넘기기보다 네이티브에서 필요한 값만 넘기는 편이 디버깅과 타입 유지에 유리하다.

성능 문제는 먼저 측정한다

Nitro가 빠른 벤치마크를 제시한다고 해서 모든 앱이 Nitro로 바꿔야 하는 것은 아니다. 네이티브 호출이 병목인지, 렌더링이 병목인지, DB 쿼리가 병목인지 먼저 측정해야 한다. 호출 빈도가 낮은 기능이라면 TurboModule의 공식성과 유지보수성이 더 큰 장점일 수 있다.

라이브러리 선택 시 New Architecture 지원 상태를 확인한다

React Native 0.76 이후 New Architecture 기본 활성화 흐름이 강화되면서, 오래된 네이티브 라이브러리는 빌드나 런타임에서 문제가 생길 수 있다. 라이브러리를 선택할 때는 README의 New Architecture 지원 여부, 최근 릴리스 날짜, 열린 이슈, RN 버전 호환 범위를 같이 확인해야 한다.

FAQ

TurboModule과 Nitro는 서로 대체 관계인가요?

완전히 같은 층의 기술은 아니다. TurboModule은 React Native 공식 네이티브 모듈 시스템이고, Nitro는 JSI 위에서 더 빠르고 객체 지향적인 바인딩을 제공하는 별도 프레임워크다. 단순 앱 내부 모듈은 TurboModule이 자연스럽고, 고성능 객체 모델이 필요한 라이브러리는 Nitro가 더 적합할 수 있다.

React Native New Architecture를 꺼도 TurboModule을 쓸 수 있나요?

일반적으로 TurboModule은 New Architecture 흐름과 함께 생각하는 것이 맞다. 공식 문서는 New Architecture 전용 Turbo Native Module 예시와 Legacy Architecture까지 지원하는 별도 호환 가이드를 구분한다. 기존 앱에서 양쪽을 모두 지원해야 한다면 호환 계층을 따로 설계해야 한다.

Nitro를 쓰면 앱이 무조건 빨라지나요?

아니다. Nitro의 장점은 네이티브 호출 경계와 객체 모델에서 두드러진다. 앱의 병목이 렌더링, 네트워크, 서버 응답, DB 설계, JS 상태 관리라면 Nitro를 도입해도 체감 성능이 크게 바뀌지 않을 수 있다.

신규 React Native 라이브러리를 만든다면 무엇을 선택해야 하나요?

공식 생태계와 장기 호환성이 최우선이면 TurboModule을 먼저 검토한다. 반대로 이미지/비디오/오디오/프레임 처리처럼 네이티브 객체를 계속 다루고 호출 빈도가 높은 라이브러리라면 Nitro를 후보에 넣을 만하다. 단, 팀이 Swift C++ interop, Android NDK, CMake 로그까지 볼 수 있어야 운영 부담을 감당할 수 있다.

결론

React Native에서 TurboModule은 “공식 New Architecture의 네이티브 모듈 표준”에 가깝고, Nitro Modules는 “JSI 기반 고성능 객체 바인딩 프레임워크”에 가깝다. 둘 다 브리지 시대의 한계를 줄이려는 방향은 같지만, 선택 기준은 다르다.

앱 내부에서 단순한 네이티브 API를 연결한다면 TurboModule부터 시작하는 편이 안전하다. 반대로 네이티브 객체를 JavaScript에서 오래 들고 다니며 자주 호출해야 하거나, 라이브러리 수준에서 성능과 타입 안정성을 강하게 요구한다면 Nitro를 검토할 가치가 있다. 중요한 것은 기술 이름만 보고 고르는 것이 아니라, 현재 프로젝트의 React Native 버전, 빌드 환경, 팀의 네이티브 디버깅 역량, 실제 성능 병목을 함께 보는 것이다.

참고 자료

  • React Native 공식 문서 – About the New Architecture: https://reactnative.dev/docs/the-new-architecture/landing-page
  • React Native 공식 문서 – Native Modules: Introduction: https://reactnative.dev/docs/turbo-native-modules-introduction
  • React Native 블로그 – New Architecture is here: https://reactnative.dev/blog/2024/10/23/the-new-architecture-is-here
  • React Native 0.75 릴리스 노트: https://reactnative.dev/blog/2024/08/12/release-0.75
  • Nitro 공식 문서 – What is Nitro?: https://nitro.margelo.com/docs/getting-started/what-is-nitro
  • Nitro 공식 문서 – Comparison: https://nitro.margelo.com/docs/resources/comparison
  • Nitro 공식 문서 – Minimum Requirements: https://nitro.margelo.com/docs/getting-started/minimum-requirements
  • Nitro GitHub 저장소: https://github.com/mrousavy/nitro
  • React Native GitHub 이슈 검색 – TurboModule Codegen: https://github.com/react/react-native/issues?q=TurboModule+Codegen
  • Nitro GitHub 이슈 검색 – build/NDK/Xcode: https://github.com/mrousavy/nitro/issues