Developer Lab · React Native
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, Performance, and Security
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.
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.
Installation
Bare React Native
npm install react-native-get-random-values uuid
cd ios && pod installImport react-native-get-random-values before uuid in your entry file.
Expo managed workflow
npx expo install expo-cryptoUse expo-crypto for UUID generation in Expo managed projects.
Frequently Asked Questions
How do I generate a UUID in React Native?
React Native has no native crypto.getRandomValues, so install react-native-get-random-values and import it once at the top of your entry file, then use the uuid package (import { v4 as uuidv4 } from 'uuid'). In Expo projects you can call Crypto.randomUUID() from expo-crypto instead. Never use Math.random() for IDs, since it is not cryptographically secure.
Is uuidv4() cryptographically secure?
Yes. uuidv4() uses the platform CSPRNG (operating system secure random source), suitable for session tokens, API keys, and idempotency keys. Do not use non-cryptographic random sources for security-sensitive identifiers.
What is the difference between UUID v4 and v7 in React Native?
UUID v4 (uuidv4() or equivalent) is fully random and not sortable. UUID v7 embeds a millisecond timestamp for chronological sorting (RFC 9562). Use v4 for general-purpose IDs; use v7 for database primary keys at scale.
Do I need to install a package for UUID generation in React Native?
A package or library install may be required. See the Installation section for the recommended approach in React Native.
How do I validate a UUID string in React Native?
Use the platform's UUID parse/validation function, or test against the RFC 4122 regex: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i. Always validate external input at API boundaries.
Should I use UUIDs as database primary keys in React Native applications?
UUIDs work well as primary keys for distributed systems. Prefer native UUID/BINARY(16) column types over VARCHAR(36). For very large tables, consider UUID v7 for better B-tree insert locality.
Can I generate UUIDs in React Native without a network connection?
Yes. UUID generation uses local OS entropy sources and does not require network access. Each call is independent and thread-safe on modern platforms.
What output formats are available in React Native?
The standard hyphenated lowercase string (36 chars) is the default. Most APIs also support 32-char hex (no hyphens) and 16-byte binary formats. Use string format for APIs and binary for database storage.
What RFC standards apply to React Native UUID generation?
Version 4 UUIDs follow RFC 4122. UUID v7 follows RFC 9562 (May 2024). Ensure your chosen method produces compliant version and variant bits.
When should I avoid UUID v1?
Avoid UUID v1 in security-sensitive contexts - it embeds MAC address and timestamp information. Prefer v4 (uuidv4() or equivalent) unless you need legacy Cassandra timeuuid compatibility.
Key definitions
- UUID
- 128-bit universally unique identifier, usually shown as 36 hex characters with hyphens.
- CSPRNG
- Cryptographically secure pseudo-random number generator - the entropy source behind secure UUID generation.
- RFC 4122
- IETF standard defining UUID versions 1 through 5. Version 4 is random.
- RFC 9562
- IETF standard adding UUID versions 6, 7, and 8. Version 7 is time-ordered.