The nanoid vs Math.random() vs Date.now() — What's the Best Way to Generate Unique IDs in JavaScript?


When you're building features like a to-do list, a chat app, or anything that dynamically creates items, you'll need unique IDs. And it’s tempting to go with what you already know:
const id1 = Math.random();
const id2 = Date.now();
But wait up… is that safe?
Let’s break it down with some real-developer talk — not your 12th-grade physics class 😅.
⚠️ The Problem: Duplicate IDs = Bugs
Imagine your React app rendering a list of tasks, and suddenly... 🔥 two tasks have the same ID.
React freaks out. Your state gets messed up. Users start throwing phones.
Why? Because you trusted Math.random()
or Date.now
()
too much.
🧪 Option 1: Math.random()
const id = Math.random().toString(36).substr(2, 9);
✅ Pros:
Super easy to write
No imports needed
❌ Cons:
Can generate duplicate IDs if called quickly (especially during fast loops or async updates)
Not really random — it's pseudo-random
Not cryptographically secure
🕒 Option 2: Date.now
()
const id = Date.now();
✅ Pros:
Gives you a timestamp
Always increasing (sort of)
❌ Cons:
Only accurate to the millisecond
Two IDs generated in the same millisecond = 💥 Collision
Still not safe for fast, repeated operations
🔐 Option 3: nanoid
(The Rockstar 🤘)
import { nanoid } from '@reduxjs/toolkit';
// or: import { nanoid } from 'nanoid';
const id = nanoid(); // "V1StGXR8_Z5jdHi6B-myT"
✅ Pros:
Super low chance of duplicate IDs
Fast and tiny
Safe even when generating thousands of IDs per second
Used by real-world apps like Redux Toolkit, Vite, and more
❌ Cons:
- You need to install a package (but trust me — it's worth it)
npm install nanoid
📊 Quick Comparison:
Method | Collision Risk | Easy to Use | Safe for Production? |
Math.random | High | ✅ Yes | ❌ Nope |
Date.now | Medium | ✅ Yes | ❌ Risky |
nanoid | Very Low | ✅ Easy | ✅ Safe |
💡 Real Example in Redux Toolkit
import { createSlice, nanoid } from '@reduxjs/toolkit';
const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
addTodo: {
reducer(state, action) {
state.push(action.payload);
},
prepare(text) {
return {
payload: {
id: nanoid(), // ← unique ID
text,
completed: false
}
};
}
}
}
});
🎯 Final Thoughts
If you're building anything where IDs must be unique, don’t gamble with Math.random()
or Date.now
()
.
Use
nanoid()
— it’s small, fast, and safe. Just like the best dev tools should be.
Subscribe to my newsletter
Read articles from Nitin Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
