Disclosure: I build Nitrakit, the video editor SDK used in this post.
Your users want to make video in your app, and "trim and post" isn't enough for them. This guide shows how to add a complete React Native video editor to your app, Expo included, with Nitrakit: install, show the editor, use your own media library and export an MP4. The code
comes straight from the React Native guide in our docs.
Why the editor belongs inside your app
When editing happens somewhere else, users leave. They export, switch apps, edit, and maybe come back to post. Each step is a chance to lose the post, and the moment of making something happens in someone else's product instead of yours.
The other option, building the editor yourself, means a timeline, text, captions, effects, audio and export, on iOS and Android, kept working release after release. For most app teams that is a second product, and it pulls engineers off the one you're actually building.
Nitrakit is the third option: a complete editor you add as a component, styled as your app.
What your users get
The editor your users already know how to use:
- A preview that plays in real time. Users tap a layer to select it, then drag, pinch or use its handles to move, resize and rotate it.
- A timeline with tools. Trim, split, speed, volume, effects, transitions, text with animations, audio, and undo.
- Word-timed captions from your app's own speech-to-text, so you choose the provider.
- Export to MP4 on the device, while the user keeps editing.
Editing and export run on the user's device, so there's no video server for you to run. Projects save as JSON that you own, so users can come back to a draft later or on another device.
What stays yours: where media comes from and where it's stored, the wording, and the look of the whole editor. More on that below.
Requirements
From the React Native guide:
- React Native with the New Architecture (the default since 0.76) and
react-native-nitro-modules. - iOS 16 or later; Android 8.0 or later (
minSdkVersion26). - Expo: a development build. Expo Go can't load the SDK's native code.
If you're on Expo, that last point is the only difference: you run your own development build instead of Expo Go, as you would for any library with native code.
Install the React Native video editor
The SDK is on npm, so there's nothing to set up first. The full steps are on the install page.
npm install @nitrakit/react-native react-native-nitro-modules
-
iOS: run
pod install. If users pick from their photo library, addNSPhotoLibraryUsageDescriptionto yourInfo.plist. - Android: nothing extra to add.
Raise minSdkVersion to 26 if it's lower.
Add it to an Expo app
On Expo, add the config plugin to app.json instead of editing native files. It sets the
Android version for you:
{ "expo": { "plugins": ["@nitrakit/react-native"] } }
Then run npx expo prebuild and build your development build as usual. Your team keeps the Expo workflow it already has.
Create a project
An editor holds one project and its undo history. Create it with your output size and frame rate, then add the user's first video:
import { createEditor, importFile } from '@nitrakit/react-native'
const editor = createEditor(1080, 1920, 30)
const media = editor.addMedia(assetId, importFile(pickedUri, 'clip.mp4'), 'clip.mp4')
const track = editor.addTrack('visual', true)
editor.insertMedia(track, media.source, 0, 0, media.durationUs)
assetId is your app's id for the file, for example its key in your storage. Projects refer
to media only by these ids, which is what lets a project sync through your backend and reopen
on another device. See Projects and media
for signed URLs and the media resolver.
Show the editor
Two components make up the editor. NitrakitPreview plays the project; NitrakitEditor has the timeline, tools and panels. Give both the same editor and they stay in sync:
import { NitrakitEditor, NitrakitPreview } from '@nitrakit/react-native'
export function EditorScreen({ editor }: { editor: Editor }) {
return (
<View style={{ flex: 1, backgroundColor: '#000' }}>
<NitrakitPreview editor={editor} style={{ flex: 1 }} />
<NitrakitEditor editor={editor} style={{ height: 400 }} onRequest={onRequest} />
</View>
)
}
Create the editor once per project (in a useMemo or your state store), not on every render.
Because they're two components, the layout is yours. Show both, only the timeline, or only the preview with controls you build; the layouts page
covers each.
Use your own media library with onRequest
The editor never opens the photo library or a file browser itself. When the user taps
Add media, picks a font or a colour, the editor asks your app through onRequest. So the screen the user sees is yours, in your design, and media can come from the camera roll, your own content library or your backend.
Return the answer, or a promise of it. Return null if the user backed out, or nothing to let the SDK show its built-in picker:
async function onRequest(request: EditorRequest) {
switch (request.kind) {
case 'addMedia':
case 'addOverlay':
case 'addAudio':
case 'addSticker': {
const picked = await pickFromLibrary() // your picker
if (!picked) return null
const path = importFile(picked.uri, picked.fileName)
const media = editor.addMedia(startUpload(path), path, picked.fileName) // your storage's id
return { source: media.source }
}
}
// anything else: the built-in picker
}
The built-in pickers cover fonts, colours, text, text styles and filters, so you can start with media only and replace the rest when your designers get to it. Every request and its answer is on the Pickers page.
Export an MP4
Export renders the project to an MP4 in the background, while the user keeps editing:
import { filesDir } from '@nitrakit/react-native'
const path = `${filesDir()}/export-${Date.now()}.mp4`
try {
await editor.exportVideo(path, editor.exportSettings(1080), (f) => setProgress(f))
// the file at `path` is ready to save, share or upload
} catch (e) {
// failed, or cancelled with editor.cancelExport()
}
What happens to the file next is up to your app: save it to the photo library, share it, or upload it to your backend. Settings, progress and cancelling are on the Export page.
Make it look like your app
Product and design teams push back on a screen that looks borrowed.
The editor takes your theme as a prop:
<NitrakitEditor
editor={editor}
theme={{
background: '#101418',
bar: '#0b0e11',
accent: '#2ee6a6',
font: 'Brand Sans',
clips: { video: '#3355ff', audio: '#18a058' },
}}
/>
Beyond colours and fonts, you can remove tools you don't offer, add your own, swap the icons, and rename every label in your users' languages. It's all set at runtime, so it can follow your app's dark mode, feature flags and language. See Customisation.
Curious what it adds to your app's download? The App size page lists it per platform, including React Native.
Before you ship
Everything above works without a license key while you build and test. A release build needs one, set once at startup; the License key page shows how.
Next steps
Follow the React Native guide in a development build, or try the editor first in the browser demo. If your app is native, there are versions of this post for iOS and Android.
I'm most interested in how this feels to integrate from the React Native side: the Expo setup, the onRequest pattern, anything that fights your navigation or state management. Comments are open.
Originally published on the Nitrakit blog.

Top comments (0)