Skip to main content

Searching...

Tools
Articles
View All Results

Developer Lab · Flutter

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

Production Ready
dart
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)

dart
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

dart
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

dart
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

dart
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

dart
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

dart
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, Performance, and Security

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.

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.

Installation

UUID v4 (uuid package)

bash
flutter pub add uuid

Works on Flutter 3.0+ (Dart 2.17+). No native linking, no pod install, no Android Gradle changes needed.

Frequently Asked Questions

How do I generate a UUID in Flutter?

Flutter uses the same Dart uuid package, which works identically on iOS, Android, Web, and Desktop. Add uuid to pubspec.yaml, then create const uuid = Uuid(); and call uuid.v4() for a random UUID or uuid.v7() for a time-ordered one.

Is Uuid().v4() cryptographically secure?

Yes. Uuid().v4() 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 Flutter?

UUID v4 (Uuid().v4() 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 Flutter?

A package or library install may be required. See the Installation section for the recommended approach in Flutter.

How do I validate a UUID string in Flutter?

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 Flutter 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 Flutter 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 Flutter?

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 Flutter 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 (Uuid().v4() 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.