The Vega Developer Tools enable you to write C++ code via Turbo Modules to run within your apps. Turbo Modules provide significant performance benefits by running lower-level code, and they support code reusability from any existing projects and services your project requires.
This guide covers performance improvements when using Turbo Modules and C++ code to handle computationally-heavy background tasks, with JavaScript comparisons, sample code, and templates to try out for yourself.
Check out React Native’s docs on how Turbo Native Modules can bridge your app’s React / JavaScript logic with device-level capabilities.
Scenario: Bubble sorting 5000 elements after a Remote button press
One of the first activities in any Computer Science 101 course is sorting, and bubble sort tends to be the first method introduced due to its simplicity:

(credit: Danny Correia)
That simplicity comes at a cost, namely the runtime and performance drag compared to more advanced recursive techniques such as Quicksort. Setting the sorting technique debate aside, the focus here is on the performance benefits of offloading memory-heavy operations from JavaScript to native C++.
Step 1: Building a Vega sample to compare memory-heavy sorting tasks
Start with the standard “Hello World” sample app template (vega project generate --template helloWorld) and update it to incorporate the following logic after a specific button press occurs:
- Set a timer in your app
- Populate an array of 5000 elements in descending order
- Implement a bubble sorting algorithm to reset the large array in ascending order
- End the timer and report the results in an on-screen UI element
JavaScript example:
let startTime = performance.now();
let arr = Array(ITEMS_TO_SORT);
for (let i = 0; i < ITEMS_TO_SORT; i++) {
arr[i] = ITEMS_TO_SORT - i;
}
bblSort(arr);
let endTime = performance.now();
let elapsedTime = endTime - startTime;
// print the elapsed time in a state variable associated with an on-screen UI component
setJsOutputText(elapsedTime.toFixed(0) + ' ms elapsed');
C++ example:
let startTime = performance.now();
// create the unsorted array in JS
let arr = Array(ITEMS_TO_SORT);
for (let i = 0; i < ITEMS_TO_SORT; i++) {
arr[i] = ITEMS_TO_SORT - i;
}
// pass the array to the Turbo Module for sorting
let sortedArr = TurboCalc.sortArray(arr);
let endTime = performance.now();
let elapsedTime = endTime - startTime;
// print the elapsed time in a state variable associated with a View/Text component on-screen
setCppOutputText(elapsedTime.toFixed(2) + ' ms elapsed');
![]()
TurboCalcwill throw an error until the Turbo Module is built and integrated into the app in the next steps.
This benchmark includes the full round-trip cost: creating the array in JavaScript, marshaling it to C++, sorting, and returning the result back to JavaScript.
Step 2: Implement the sorting code in JavaScript & C++
For JavaScript, we’ll implement the bubble sort sample code:
function bblSort(totalItems) { // we are using 5000 for this example
let arr = Array(totalItems);
// create the array based on the items
for (let i = 0; i < totalItems; i++) {
arr[i] = totalItems - i;
}
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
// Checking if the item at present iteration is greater than the next iteration
if (arr[j] > arr[j + 1]) {
// If the condition is true then swap them
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
return arr;
}
For C++, we will create a new Turbo Module (via the template) named TurboCalc and add a sortArray method that accepts a JavaScript array of integers, sorts it, and returns the result:
#include <TMLog.h>
#include <vector>
#include <algorithm>
std::vector<int32_t> TurboCalc::sortArray(std::vector<int32_t> a)
{
int numbersToSort = a.size();
// Bubble sort
for (int i = 0; i < numbersToSort; i++)
{
for (int j = i + 1; j < numbersToSort; j++)
{
if (a[j] < a[i])
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
TMINFO("Print the first 10 elements for posterity...\n");
for (int i = 0; i < 10 && i < numbersToSort; i++)
{
TMINFO( std::to_string(a[i]) + "\t" );
}
return a;
}
The method accepts std::vector<int32_t> which maps directly from a TypeScript Int32[] parameter — Vega handles the marshaling automatically. See JavaScript Types in Native Code for the full type mapping.
Run vega build within the Turbo Module directory to generate a .tgz file. This file can then be incorporated into your Vega app via npm install.
You’ll also need a TypeScript spec file (e.g., NativeTurboCalc.ts) to declare the method signature for codegen:
import type {TurboModule} from 'react-native';
import {TurboModuleRegistry} from 'react-native';
import type {Int32} from 'react-native/Libraries/Types/CodegenTypes';
export interface Spec extends TurboModule {
sortArray(arr: Int32[]): Int32[];
}
export default TurboModuleRegistry.getEnforcing<Spec>('TurboCalc');
Then update your App.tsx file to import the Turbo Module:
// import our Turbo Module into our app
import {TurboCalc} from '@amzn/TurboCalc';
With this import in place, the sample code from Step 1 that calls TurboCalc.sortArray() will resolve correctly.
Step 3: Compare performance results for C++ versus JavaScript
If you had any prior doubts, C++ was ~99% faster at completing the sort.

However, keep in mind that compute times on the Fire TV stick device are going to be much slower than running on the Vega Virtual Device. There are also performance differences when running an app in debug versus release mode. For example, the numbers below show the same app running on the Fire TV stick in release mode — debug mode was 15 seconds (or 50%) slower.
(Fire TV running the Bubble Sort sample app in release mode.)
We can also use the Vega Studio Activity Monitor to see that JavaScript computing utilizes 100% of the CPU for the task:
Factors to keep in mind
Strong reminder that we DON’T recommend you sort 5000 items in JavaScript, especially with a bubble sort! Consider moving any intense processing tasks server-side before sending to your client app. However, there may be certain activities where parsing a large number of items in your app may be unavoidable such as parsing a video manifest, XML files, or video transcoding — for those scenarios, drop down to native C++ code through Turbo Modules.
It’s worth mentioning that React Native for Vega uses the Hermes JavaScript engine and our sample code in this guide has NOT been optimized with any techniques such as Ahead-of-Time Compilation (AOT) for Static Hermes. Static Hermes (Hermes v1) is coming in a future Vega SDK release as part of React Native 0.83 — while it will close some of the performance gaps, native C++ code will almost always remain faster than JavaScript for memory-heavy tasks.
Common issues when using Turbo Modules
- JavaScript apps must be rebuilt with the Turbo Module incorporated. You may need to do another
vega buildand ensure it passes with no unit test failures. - If rebuilding your Turbo Module does not reflect the latest functionality, check whether your JavaScript app is properly grabbing the latest package built:
- Delete your
package-lock.jsonfile - Remove the Turbo Modules folder under
node_modules - Re-install the SDK via the setup docs
- Using npm link may be useful here as well
- Delete your
Do you need Turbo Modules and C++ for less performance-intensive scenarios?
You probably don’t. For example, if we take the exact same scenario but only had 500 items to bubble sort, the difference is negligible on the Vega Virtual Device and doesn’t merit switching to native C++ and Turbo Modules. Just make sure you test on both the virtual device and the Fire TV device for an accurate representation of your app’s user experience.
How do I access my Turbo Module logs?
There are different ways, but the following command is handy: journalctl -f | grep Turbo which will print out logs from TMINFO.
myusername@c889f3b7 % vega device shell
Last login: Thu Nov 16 19:28:58 2023 from 10.0.2.2
simulator:~# journalctl -f | grep Turbo
Nov 26 23:33:00.083563 amazon-0001bf3d402d7aa1 local0.err keplerscript-ru[929]: 41 E Volta:[KeplerScript] NapiTurboModule::get property $$typeof not found for module TurboCalc
Nov 26 23:33:04.306851 amazon-0001bf3d402d7aa1 local0.info keplerscript-ru[929]: KeplerScript.TurboModule:
Nov 26 23:33:04.312820 amazon-0001bf3d402d7aa1 local0.info keplerscript-ru[929]: KeplerScript.TurboModule: Sorted Element List ...
Nov 26 23:33:04.312838 amazon-0001bf3d402d7aa1 local0.info keplerscript-ru[929]: KeplerScript.TurboModule: 1
Nov 26 23:33:04.312839 amazon-0001bf3d402d7aa1 local0.info keplerscript-ru[929]: KeplerScript.TurboModule: 2
Nov 26 23:33:04.312841 amazon-0001bf3d402d7aa1 local0.info keplerscript-ru[929]: KeplerScript.TurboModule: 3
Full sample code
The full App.tsx for this example is below. The Turbo Module C++ code is unchanged from the template — we just added the sortArray method, and that code is already above.
(Disclaimer: this is prototype/demo code, not intended for production use.)
/**
* Copyright (c) 2022 Amazon.com, Inc. or its affiliates. All rights reserved.
*
* PROPRIETARY/CONFIDENTIAL. USE IS SUBJECT TO LICENSE TERMS.
*/
import React, {useRef, useState} from 'react';
import {
ColorValue,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import {TurboCalc} from '@amzn/TurboCalc';
const backgroundColors = ['#283593', '#2382CB', '#A670F2', '#029976'];
export const App = () => {
const ITEMS_TO_SORT = 5000;
const [backgroundColor, setBackgroundColor] = useState<ColorValue>(
backgroundColors[0],
);
const colorIdx = useRef<number>(0);
const [jsOutputText, setJsOutputText] = useState('Waiting to start..');
const [cppOutputText, setCppOutputText] = useState('Waiting to start..');
function bblSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
const styles = getStyles(backgroundColor);
const handleButtonPress = () => {
const nextColor = (colorIdx.current + 1) % backgroundColors.length;
setBackgroundColor(backgroundColors[nextColor]);
colorIdx.current = nextColor;
let startTime = performance.now();
let arr = Array(ITEMS_TO_SORT);
for (let i = 0; i < ITEMS_TO_SORT; i++) {
arr[i] = ITEMS_TO_SORT - i;
}
bblSort(arr);
let endTime = performance.now();
let elapsedTime = endTime - startTime;
setJsOutputText(elapsedTime.toFixed(0) + ' ms elapsed');
};
const handleButtonPressCpp = () => {
const nextColor = (colorIdx.current + 1) % backgroundColors.length;
setBackgroundColor(backgroundColors[nextColor]);
colorIdx.current = nextColor;
let startTime = performance.now();
let arr = Array(ITEMS_TO_SORT);
for (let i = 0; i < ITEMS_TO_SORT; i++) {
arr[i] = ITEMS_TO_SORT - i;
}
let sortedArr = TurboCalc.sortArray(arr);
let endTime = performance.now();
let elapsedTime = endTime - startTime;
setCppOutputText(elapsedTime.toFixed(2) + ' ms elapsed');
};
const hexColor = JSON.stringify(backgroundColor).replace(/"/g, '');
return (
<View style={styles.container}>
<View style={styles.headerBlock}>
<Text style={styles.headerText}>
Bubble Sort Measurement: {ITEMS_TO_SORT} Items
</Text>
</View>
<View style={styles.horizontalView}>
<TouchableOpacity
style={styles.button}
onPress={handleButtonPress}
testID="sampleButton">
<Text style={styles.buttonLabel}>Calculate JavaScript</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={handleButtonPressCpp}
testID="sampleButton">
<Text style={styles.buttonLabel}>Calculate C++</Text>
</TouchableOpacity>
</View>
<View style={styles.horizontalView}>
<View style={styles.textView}>
<Text style={styles.textBlock}>{jsOutputText}</Text>
</View>
<View style={styles.textView}>
<Text style={styles.textBlock}>{cppOutputText}</Text>
</View>
</View>
<Text style={styles.colorLabel}>{hexColor}</Text>
</View>
);
};
const getStyles = (bgColor: ColorValue) =>
StyleSheet.create({
horizontalView: {
flexDirection: 'row',
},
textView: {
height: 300,
width: 300,
padding: 15,
},
textBlock: {
color: 'white',
fontSize: 30,
textAlign: 'center',
},
headerBlock: {
paddingBottom: 50,
},
headerText: {
fontSize: 50,
color: 'white',
fontStyle: 'italic',
},
container: {
flex: 1,
flexDirection: 'column',
backgroundColor: bgColor,
justifyContent: 'center',
alignItems: 'center',
},
button: {
alignItems: 'center',
backgroundColor: '#303030',
borderColor: 'navy',
borderRadius: 10,
borderWidth: 1,
paddingVertical: 12,
paddingHorizontal: 32,
margin: 20,
},
buttonLabel: {
color: 'white',
fontSize: 25,
fontFamily: 'Amazon Ember',
},
colorLabel: {
color: 'white',
position: 'absolute',
top: 32,
right: 32,
fontSize: 32,
},
});
Related resources
- Create a Turbo Module — Official guide to creating and integrating Turbo Modules
- Advanced Turbo Module Topics — Threading, async patterns, and complex data types
- App Performance Best Practices — General performance guidance for Vega apps
- Monitor CPU Usage — Using Vega Studio Activity Monitor
- Turbo Native Modules (React Native docs) — React Native’s architecture overview
Last updated: May 12, 2026



