Generate UUID in Flutter
Flutter uses the same Dart uuid package — works identically on iOS, Android, Web, and Desktop. One package, one API, all platforms. No native code, no platform channels.
Quick Reference
| Method | Version | Sortable | Use Case |
|---|---|---|---|
| uuid.v4() | v4 | No | Widget keys, model IDs, session tokens |
| uuid.v7() | v7 | Yes | Local DB PKs (Hive, SQFlite, Isar) |
| uuid.v5() | v5 | No | Deterministic — deduplication, content IDs |
Primary Implementation
import 'package:uuid/uuid.dart'; // Declare once at the top level — reuse everywhere const _uuid = Uuid(); // UUID v4 — random, CSPRNG-backed, works on all Flutter platforms final id = _uuid.v4(); print(id); // → f47ac10b-58cc-4372-a567-0e02b2c3d479 // UUID v7 — time-ordered, great for local database PKs final idV7 = _uuid.v7(); // Generate multiple final ids = List.generate(5, (_) => _uuid.v4());
All UUID Versions
UUID v4 — Random (recommended default)
import 'package:uuid/uuid.dart'; const uuid = Uuid(); final id = uuid.v4(); print(id); // → "550e8400-e29b-41d4-a716-446655440000"
Flutter model with UUID — Hive local database
import 'package:hive/hive.dart';
import 'package:uuid/uuid.dart';
const _uuid = Uuid();
part 'note.g.dart';
@HiveType(typeId: 0)
class Note extends HiveObject {
@HiveField(0)
final String id;
@HiveField(1)
String title;
@HiveField(2)
String content;
Note({
String? id,
required this.title,
required this.content,
}) : id = id ?? _uuid.v4();
}
SQFlite — UUID primary key
import 'package:sqflite/sqflite.dart';
import 'package:uuid/uuid.dart';
const _uuid = Uuid();
Future<void> createTable(Database db) async {
await db.execute('''
CREATE TABLE IF NOT EXISTS tasks (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
completed INTEGER NOT NULL DEFAULT 0
)
''');
}
Future<String> insertTask(Database db, String title) async {
final id = _uuid.v4();
await db.insert('tasks', {'id': id, 'title': title, 'completed': 0});
return id;
}
Real-World Use Cases
1. ListView with stable item keys
import 'package:flutter/material.dart';
import 'package:uuid/uuid.dart';
const _uuid = Uuid();
class TodoItem {
final String id;
final String text;
bool done;
TodoItem(this.text) : id = _uuid.v4(), done = false;
}
class TodoList extends StatefulWidget {
const TodoList({super.key});
@override
State<TodoList> createState() => _TodoListState();
}
class _TodoListState extends State<TodoList> {
final List<TodoItem> _items = [];
void _addItem(String text) {
setState(() => _items.add(TodoItem(text)));
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _items.length,
itemBuilder: (context, index) {
final item = _items[index];
return ListTile(
key: ValueKey(item.id), // UUID as stable widget key
title: Text(item.text),
);
},
);
}
}
2. Riverpod state management — UUID entity IDs
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:uuid/uuid.dart';
const _uuid = Uuid();
class Note {
final String id;
final String content;
const Note({required this.id, required this.content});
}
class NotesNotifier extends StateNotifier<List<Note>> {
NotesNotifier() : super([]);
void add(String content) {
state = [...state, Note(id: _uuid.v4(), content: content)];
}
void remove(String id) {
state = state.where((n) => n.id != id).toList();
}
}
final notesProvider = StateNotifierProvider<NotesNotifier, List<Note>>(
(ref) => NotesNotifier(),
);
3. Offline-first sync — generate IDs before server confirmation
import 'package:uuid/uuid.dart';
const _uuid = Uuid();
class SyncService {
// Generate UUID locally — works offline
// When connectivity returns, sync to server using the same UUID
Future<String> createRecord(Map<String, dynamic> data) async {
final id = _uuid.v4();
data['id'] = id;
// Save locally first
await localDb.insert(data);
// Queue for sync when online
await syncQueue.add({'id': id, 'data': data, 'action': 'create'});
return id; // Return immediately — no server round-trip needed
}
}
Common Mistakes
Calling Uuid().v4() inside a build() method
Generating a UUID inside build() creates a new ID on every rebuild, breaking widget identity and causing unnecessary re-renders. Always generate UUIDs in model constructors or state initialization.
Not using ValueKey(item.id) in list widgets
Without a stable key, Flutter's diffing algorithm can't track items correctly when the list changes. Use key: ValueKey(item.id) in ListView.builder and AnimatedList for correct animations and state preservation.
Creating a new Uuid() instance on every call
Declare const _uuid = Uuid() once at the top of your file or as a static field. The instance is stateless and safe to reuse — creating a new one each time is unnecessary overhead.
How It Works
The uuid package is pure Dart — no native code, no platform channels. It uses dart:math's Random.secure() which maps to the OS CSPRNG on every Flutter platform.
This means the same code works identically on iOS, Android, Web (using crypto.getRandomValues), macOS, Windows, and Linux — no conditional imports needed.
Output Example
uuid.v4()
f47ac10b-58cc-4372-a567-0e02b2c3d479
uuid.v7() — time-ordered
018e8f6a-1b2c-7d3e-9f4a-5b6c7d8e9f0a
Best Practices
Generate UUIDs in model constructors, not in build() methods.
Use ValueKey(item.id) in list widgets for correct diffing and animations.
Use uuid.v7() for local database PKs — sequential inserts are faster in B-tree indexes.
Performance
UUID generation is negligible overhead in Flutter. The pure-Dart implementation runs in AOT-compiled code with no native bridge latency.
Generating UUIDs for list items, form fields, or local DB records has zero measurable impact on frame rate or UI responsiveness.
Installation
flutter pub add uuid
Works on Flutter 3.0+ (Dart 2.17+). No native linking, no pod install, no Android Gradle changes needed.
Security
Entropy source: Random.secure() — OS CSPRNG on all platforms. iOS: SecRandomCopyBytes. Android: SecureRandom. Web: crypto.getRandomValues.
Cryptographically secure on all Flutter platforms. Suitable for session tokens, device IDs, and API keys.