Generate UUID in React Native
React Native has no native crypto.randomUUID() — you need a polyfill. The standard approach is react-native-get-random-values + uuid, or expo-crypto on Expo projects.
Quick Reference
| Approach | Works on | Expo | Use Case |
|---|---|---|---|
| rn-get-random-values + uuid | iOS + Android | Yes (bare) | Recommended for bare React Native |
| expo-crypto | iOS + Android + Web | Yes (managed) | Recommended for Expo managed workflow |
| react-native-uuid | iOS + Android | Yes | Simpler API, single package |
Primary Implementation
// STEP 1: Install packages
// npm install react-native-get-random-values uuid
// STEP 2: Import the polyfill at the TOP of your entry file (index.js or App.js)
// This MUST be the very first import — before anything else
import 'react-native-get-random-values';
// STEP 3: Now you can use the uuid package normally
import { v4 as uuidv4 } from 'uuid';
// Generate a UUID v4
const id = uuidv4();
console.log(id);
// → "f47ac10b-58cc-4372-a567-0e02b2c3d479"
// Generate multiple
const ids = Array.from({ length: 5 }, () => uuidv4());
// Validate a UUID
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
const isValidUUID = (str) => UUID_REGEX.test(str);
All Approaches
Expo managed workflow — expo-crypto
// npx expo install expo-crypto import * as Crypto from 'expo-crypto'; // Generate a UUID v4 — works on iOS, Android, and Web const id = Crypto.randomUUID(); console.log(id); // → "f47ac10b-58cc-4372-a567-0e02b2c3d479" // expo-crypto also provides randomBytes for custom entropy needs const bytes = await Crypto.getRandomBytesAsync(16);
react-native-uuid — single package, no polyfill needed
// npm install react-native-uuid import uuid from 'react-native-uuid'; // No polyfill import needed — handles entropy internally const id = uuid.v4(); console.log(id); // → "f47ac10b-58cc-4372-a567-0e02b2c3d479"
TypeScript — typed UUID generation
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';
// Branded type for type safety
type ItemId = string & { readonly _brand: 'ItemId' };
function createItemId(): ItemId {
return uuidv4() as ItemId;
}
interface ListItem {
id: ItemId;
title: string;
completed: boolean;
}
function createItem(title: string): ListItem {
return { id: createItemId(), title, completed: false };
}
Real-World Use Cases
1. FlatList with stable item keys
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';
import { FlatList, Text, TouchableOpacity } from 'react-native';
import { useState } from 'react';
export default function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = (text) => {
setTodos(prev => [...prev, { id: uuidv4(), text, done: false }]);
};
return (
<FlatList
data={todos}
keyExtractor={item => item.id} // UUID as stable key
renderItem={({ item }) => <Text>{item.text}</Text>}
/>
);
}
2. AsyncStorage — unique device ID
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';
import AsyncStorage from '@react-native-async-storage/async-storage';
const DEVICE_ID_KEY = '@device_id';
async function getDeviceId() {
let id = await AsyncStorage.getItem(DEVICE_ID_KEY);
if (!id) {
id = uuidv4();
await AsyncStorage.setItem(DEVICE_ID_KEY, id);
}
return id;
}
3. Optimistic UI — assign ID before API call
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';
async function addComment(postId, text, setComments) {
const tempId = uuidv4();
const optimisticComment = { id: tempId, text, status: 'pending' };
// Immediately show in UI
setComments(prev => [...prev, optimisticComment]);
try {
const response = await fetch(`/api/posts/${postId}/comments`, {
method: 'POST',
headers: { 'Idempotency-Key': tempId },
body: JSON.stringify({ text }),
});
const saved = await response.json();
// Replace temp with server-confirmed comment
setComments(prev => prev.map(c => c.id === tempId ? saved : c));
} catch {
// Remove on failure
setComments(prev => prev.filter(c => c.id !== tempId));
}
}
Common Mistakes
Not importing the polyfill first
import 'react-native-get-random-values' MUST be the very first import in your entry file (index.js). If it comes after other imports, the polyfill may not be applied in time and uuid will throw an error about missing crypto.getRandomValues.
Using Math.random() for IDs
Math.random() is not CSPRNG-backed and only provides ~53 bits of entropy. It is not suitable for unique IDs in any production app. Always use the polyfill + uuid approach.
Forgetting to run pod install after installing the polyfill
react-native-get-random-values has native iOS code. After npm install, run cd ios && pod install to link the native module. Skipping this causes a crash on iOS.
Using the polyfill approach in Expo managed workflow
In Expo managed workflow, you cannot use native modules that require pod install. Use expo-crypto instead — it's part of the Expo SDK and works without ejecting.
How It Works
React Native's JavaScript engine (Hermes or JSC) does not expose crypto.getRandomValues() by default. The react-native-get-random-values polyfill bridges to the native OS CSPRNG — SecRandomCopyBytes on iOS and SecureRandom on Android.
Once the polyfill is in place, the uuid package works exactly as it does in a browser or Node.js environment.
expo-crypto takes a different approach — it calls the native module directly without needing a global polyfill, making it cleaner for Expo projects.
Output Example
uuidv4()
f47ac10b-58cc-4372-a567-0e02b2c3d479
Crypto.randomUUID() (expo-crypto)
f47ac10b-58cc-4372-a567-0e02b2c3d479
Best Practices
Put the polyfill import as the absolute first line of index.js.
Use expo-crypto in Expo managed workflow — no native linking needed.
Use UUIDs as keyExtractor in FlatList for stable, efficient list rendering.
Performance
UUID generation is fast — the native bridge call is minimal overhead. Generating UUIDs for list items, form fields, or optimistic updates has no measurable impact on UI performance.
The polyfill is synchronous — no async/await needed for UUID generation.
Installation
# Bare React Native
npm install react-native-get-random-values uuid
cd ios && pod install
# Expo managed workflow
npx expo install expo-crypto
# Simpler alternative (any RN project)
npm install react-native-uuid
Security
iOS entropy source: SecRandomCopyBytes — Apple's CSPRNG. Cryptographically secure.
Android entropy source: java.security.SecureRandom — backed by the OS entropy pool. Cryptographically secure.
Suitable for session tokens, device IDs, and API keys in mobile apps.