React Native in the cloud
You don't need a Mac or Android Studio to build a React Native app. Spinini's Node.js containers have everything you need to scaffold, develop, and preview an Expo app — then hand off the build to Expo's cloud service.
Step 1 — Create a Node.js Project
From your dashboard, click New Project → Node.js. Name it something like "my-expo-app". The Node.js container comes with Node 20 and npm pre-installed, which is all Expo needs.
Step 2 — Scaffold the Expo App
Open the Terminal tab and run:
npx create-expo-app@latest . --template blank
npm installThis creates a standard Expo project with App.js as your entry point. The file tree updates immediately — you'll see app.json, App.js, babel.config.js, and the assets/ folder.
Step 3 — Start the Expo Dev Server
npx expo start --webThe --web flag starts Expo's web renderer, which runs your React Native components in the browser. Once it starts, click the Preview tab — you'll see your app running as a web app. This is a fast way to iterate on layout and logic.
Step 4 — Preview on Your Phone with Expo Go
For a real device preview:
1. Install Expo Go on your iOS or Android phone (free from the App Store / Play Store)
2. In the terminal, run npx expo start (without --web)
3. The terminal shows a QR code
4. Open Expo Go and scan the QR code
Your phone connects to Spinini's container over the network and loads your app. Every time you save a file, the app hot-reloads on your phone instantly.
Note: Your phone and Spinini need to be able to reach each other. This works best when your phone is on the same WiFi network. If it doesn't connect automatically, Expo Go also supports tunnel mode — run npx expo start --tunnel and it routes through Expo's servers.
Step 5 — Build Your App
Edit App.js to build your UI:
import { StyleSheet, Text, View, TouchableOpacity, useState } from 'react-native';
export default function App() {
const [count, setCount] = useState(0);
return (
<View style={styles.container}>
<Text style={styles.title}>My Spinini App</Text>
<Text style={styles.count}>{count}</Text>
<TouchableOpacity style={styles.button} onPress={() => setCount(c => c + 1)}>
<Text style={styles.buttonText}>Tap me</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: '#0e0e10' },
title: { fontSize: 24, fontWeight: 'bold', color: '#f0f0f2', marginBottom: 20 },
count: { fontSize: 64, color: '#f97316', marginBottom: 30 },
button: { backgroundColor: '#f97316', paddingHorizontal: 32, paddingVertical: 14, borderRadius: 12 },
buttonText: { color: 'white', fontWeight: '600', fontSize: 16 },
});Or ask the AI Agent to build the whole UI for you — describe your screens and it writes the components.
Step 6 — Install Packages
Install any React Native compatible package the same way:
npm install @react-navigation/native @react-navigation/stack
npx expo install react-native-screens react-native-safe-area-contextStep 7 — Build an APK or IPA
For a production build, use Expo's cloud build service (EAS Build):
npm install -g eas-cli
eas login
eas build --platform android --profile previewEAS Build runs the native build on Expo's servers (not in your Spinini container). The result is an APK you can install directly or an AAB for the Play Store. iOS builds work the same way with --platform ios and an Apple Developer account.
Tips
- Use the AI Chat panel to ask questions about React Native APIs — "how do I use the camera in Expo?" saves you digging through docs.
- Save a Version History checkpoint before major refactors so you can roll back.
- Keep your
app.jsonslug unique — it's the identifier Expo uses for your app. - The web preview (
--web) is fastest for iteration but doesn't perfectly match native behavior. Always test on a real device before shipping.