React Native Native

React Native Native

Drop a .rs, .cpp, .mm, .kt, .swift, or .zig file right next to your JS components. It compiles on save, hot-reloads to your device, and just works — no Xcode, no Android Studio.

Native code lives next to your JS

Import native files like any other module. No separate project, no context switching.

// App.tsx — native files import like any other module
import HelloRust from './HelloRust';
import { add, greet } from './math_utils';
import { getColorScheme } from './device_info';
import { tapMedium } from './haptics';
import ComposeCard from './ComposeCard';
import SwiftCounter from './SwiftCounter';

export default function App() {
  return (
    <View>
      <HelloRust text="From JS!" r={0.2} g={0.9} b={0.9} />
      <ComposeCard title="Hello Compose!" />
      <SwiftCounter title="SwiftUI!" r={0.9} g={0.5} b={0.9} />
      <Text>{greet("world")}</Text>
      <Text>{getColorScheme()}</Text>
      <Pressable onPress={() => tapMedium()}>
        <Text>Haptic</Text>
      </Pressable>
    </View>
  );
}

Pick your language

🦀

Rust

use nativ_core::prelude::*;

#[component]
pub struct HelloRust {
    text: String,
    r: f64,
    g: f64,
    b: f64,
    on_press: Callback,
}

impl NativeView for HelloRust {
    fn mount(&mut self, view: NativeViewHandle) {
        view.set_background_color(self.r, self.g, self.b, 1.0);
        view.add_label(&self.text, 0.5, 1.0, 0.0);
    }
}

C++

#include <cmath>
#include <string>

NATIV_EXPORT(sync)
int add(int a, int b) {
    return a + b;
}

NATIV_EXPORT(sync)
double fast_inv_sqrt(double x) {
    float xf = static_cast<float>(x);
    float xhalf = 0.5f * xf;
    int i = *(int*)&xf;
    i = 0x5f3759df - (i >> 1);
    xf = *(float*)&i;
    xf = xf * (1.5f - xhalf * xf * xf);
    return static_cast<double>(xf);
}
📱

ObjC++

#import <UIKit/UIKit.h>
#include <string>

NATIV_EXPORT(sync)
std::string getColorScheme() {
    UITraitCollection *traits =
        [UITraitCollection currentTraitCollection];
    switch (traits.userInterfaceStyle) {
        case UIUserInterfaceStyleDark:  return "dark";
        case UIUserInterfaceStyleLight: return "light";
        default: return "unknown";
    }
}
🟣

Kotlin / Compose

// @nativ_component
@Composable
fun ComposeCard(title: String) {
    var count by remember { mutableIntStateOf(0) }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color(0xFC6A1B9A)),
        contentAlignment = Alignment.Center
    ) {
        Text(text = title, color = Color.White,
             fontSize = 18.sp,
             fontWeight = FontWeight.Bold)
    }
}
🍎

Swift / SwiftUI

import SwiftUI

// @nativ_component
struct SwiftCounterView: View {
    let title: String
    let color: Color

    var body: some View {
        VStack(spacing: 8) {
            Text(title)
                .font(.system(size: 18, weight: .bold))
                .foregroundColor(.white)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(color)
    }
}
⚙️

Zig

const std = @import("std");

export fn add(a: i32, b: i32) i32 {
    return a + b;
}

export fn fibonacci(n: u32) u64 {
    var a: u64 = 0;
    var b: u64 = 1;
    for (0..n) |_| {
        const tmp = a + b;
        a = b;
        b = tmp;
    }
    return a;
}

How it works

1

Write native code

Create a .rs, .cpp, .mm, .kt, .swift, or .zig file right next to your JS components. Same project, same folder.

2

Save

Metro detects the change, compiles your native code, and code-signs it automatically.

3

See it on device

Your component hot-reloads on the physical device. Sub-second feedback loop, just like JS.

Ready to go native?

Get started in under 5 minutes.

Read the docs