English | 日本語 | Русский | 简体中文 | Bahasa Indonesia | 한국어 | العربية
Генератор уникальных ID для JavaScript — лёгкий, безопасный, ID можно применять в URL.
«Поразительный уровень бессмысленного перфекционизма, который просто невозможно не уважать»
- Лёгкий. 118 байт (после минификации и Brotli). Без зависимостей. Size Limit следит за размером.
- Безопасный. Использует аппаратный генератор случайных чисел. Можно использовать в кластерах машин.
- Короткие ID. Используется больший алфавит, чем у UUID (
A-Za-z0-9_-). Поэтому длина ID уменьшена с 36 до 21 символа. - Работает везде. Nano ID уже портировали на 20 языков программирования.
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"Поддерживает современные браузеры, IE (с Babel), Node.js и React Native.
Сделано в Злых марсианах, продуктовом консалтинге для инструментов разработки.
- Оглавление
- Сравнение с UUID
- Сравнение производительности
- Безопасность
- Подключение
- API
- Руководство
- Инструменты
Nano ID похож на UUID v4 (случайный). У них сравнимое число битов случайности в ID (126 у Nano ID против 122 у UUID), поэтому они обладают похожей вероятностью возникновения коллизий (повторной генерации ранее выданных ID):
Чтобы вероятность повтора приблизилась к 1 на миллиард, нужно сгенерировать 103 триллиона ID.
Но между ними есть 2 важных отличия:
- Nano ID использует более широкий алфавит, и сравнимое количество битов случайности будут упакованы в более короткую строку (21 символ, против 36 у UUID).
- Код Nano ID в 4 раз меньше, чем у
uuid/v4— 118 байт против 423.
$ node ./test/benchmark.js
crypto.randomUUID 21,741,317 ops/sec
uuid v4 21,204,378 ops/sec
@napi-rs/uuid 10,236,615 ops/sec
uid/secure 10,567,676 ops/sec
@lukeed/uuid 8,647,481 ops/sec
nanoid 7,800,308 ops/sec
customAlphabet 9,697,350 ops/sec
nanoid for browser 576,759 ops/sec
secure-random-string 529,253 ops/sec
uid-safe.sync 526,459 ops/sec
Non-secure:
uid 31,379,525 ops/sec
nanoid/non-secure 3,678,505 ops/sec
rndm 3,767,185 ops/secСреда сравнения: Framework 13 7840U, Fedora 39, Node.js 21.6.
См. также хорошую статью о теориях генераторов случайных чисел: Secure random values (in Node.js)
-
Непредсказуемость. Вместо предсказуемого
Math.random(), Nano ID использует модульcryptoв Node.js и Web Crypto API в браузере. Эти модули дают доступ к аппаратному генератору случайных чисел. -
Равномерность. Например, существует популярная ошибка
random % alphabet, которую часто допускают при разработке генератора ID. Распределение вероятности для каждого символа может не быть одинаковым. Из-за неравномерности использования пространства алфавита, на перебор ID потребуется меньше времени, чем ожидается. Nano ID использует более совершенный алгоритм, а равномерность распределения символов покрыта тестами. -
Документация: все хитрости Nano ID хорошо документированы — смотрите комментарии в исходниках.
-
Уязвимости: если вы нашли уязвимость в Nano ID, свяжитесь с командой безопасности Tidelift. Они проконтролируют исправление и проинформируют пользователей.
Nano ID 5 работает с ESM-проектами (import) в тестах или скриптах для Node.js.
npm install nanoidНа проектах с CommonJS вы можете использовать:
-
require()будет работать в последней версия Node.js 22.12 (из коробки) или Node.js 20 (с флагом--experimental-require-module). -
В более старых версиях Node.js можно использовать динамический импорт:
let nanoid module.exports.createID = async () => { if (!nanoid) ({ nanoid } = await import('nanoid')) return nanoid() // => "V1StGXR8_Z5jdHi6B-myT" }
-
Или можно просто взять Nano ID 3.x (мы его всё ещё поддерживаем):
npm install nanoid@3
JSR это замена npm с открытым управлением и активной разработкой (в отличие от npm).
npx jsr add @sitnik/nanoidВы можете использовать пакет с JSR в Node.js, Deno, Bun.
// Replace `nanoid` to `@sitnik/nanoid` in all imports
import { nanoid } from '@sitnik/nanoid'Для Deno установите через deno add jsr:@sitnik/nanoid
или импортируйте jsr:@sitnik/nanoid.
Для быстрого прототипирования вы можете подключить Nano ID с CDN без установки. Не используйте этот способ на реальном сайте, так как он сильно бьёт по скорости загрузки сайта.
import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'Nano ID разделён на два модуля: стандартный и небезопасный.
По умолчанию используются символы, безопасные для URL (A-Za-z0-9_-).
Длина ID по умолчанию — 21 символ
(чтобы вероятность коллизий была соизмеримой с UUID v4).
Безопасный и простой в использовании способ использования Nano ID.
Из-за особенностей работы генератора случайных чисел при использовании этого способа ЦПУ может иногда простаивать без работы.
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"Функция также принимает необязательный аргумент, задающий длину ID:
nanoid(10) //=> "IRFa-VaY2b"При изменении размера, всегда проверяйте риски в нашем калькуляторе коллизий.
По умолчанию, Nano ID использует аппаратный генератор случайных чисел для получения непредсказуемых ID и минимизации риска возникновения коллизий (повторной генерации ранее выданных ID). Но если вам не требуется устойчивость к подбору ID, то вы можете перейти на небезопасный генератор — это полезно там, где нет доступа к API аппаратного генератора случайных чисел.
import { nanoid } from 'nanoid/non-secure'
const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"Но учтите, что предсказуемость ID может быть использована для атаки на систему.
Функция customAlphabet позволяет создать свою функцию nanoid
с нужным вам алфавитом и длиной ID.
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
user.id = nanoid() //=> "4f90d13a42"import { customAlphabet } from 'nanoid/non-secure'
const nanoid = customAlphabet('1234567890abcdef', 10)
user.id = nanoid()Не забудьте проверить риски коллизии вашего алфавита и длины
на нашем калькуляторе. nanoid-dictionary содержит много популярных
примеров альтернативных алфавитов.
Алфавит должен содержать ≤256 символов. Иначе мы не сможем гарантировать непредсказуемость ID.
Длину ID можно менять не только в customAlphabet(), но и при вызове
генератора, который она вернёт:
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid(5) //=> "f01a2"Функция customRandom позволяет создать свою функцию nanoid со своими
генераторами случайных чисел, алфавитом и длинной ID.
Например, можно использовать генератор c seed для повторяемости тестов.
import { customRandom } from 'nanoid'
const rng = seedrandom(seed)
const nanoid = customRandom('abcdef', 10, size => {
return new Uint8Array(size).map(() => 256 * rng())
})
nanoid() //=> "fbaefaadeb"Функция в третьем аргументе customRandom должна принимать длину массива
и возвращать нужный массив со случайными числами
Если вы хотите заменить только генератор случайных чисел, но оставить
URL-совместимый алфавит, то стандартный алфавит доступен
в экспорте urlAlphabet.
const { customRandom, urlAlphabet } = require('nanoid')
const nanoid = customRandom(urlAlphabet, 10, random)Не используйте Nano ID для генерации свойства key в JSX. При каждом рендере
key будет разный, что плохо скажется на производительности.
function Todos({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={nanoid()}>
{' '}
/* НЕ ДЕЛАЙТЕ ТАК */
{todo.text}
</li>
))}
</ul>
)
}Для связи <input> и <label> лучше использовать useId,
который был добавлен в React 18.
React Native не имеет встроенного аппаратного генератора случайных чисел. Полифил ниже работает в чистом React Native и в Expo начиная с версии 39.
- Прочитайте документацию
react-native-get-random-valuesи установите его. - Импортируйте эту библиотеку до импорта Nano ID.
import 'react-native-get-random-values'
import { nanoid } from 'nanoid'В PouchDB и CouchDB, ID не могут начинаться с _. Добавьте к ID префикс,
так как иногда Nano ID может сгенерировать ID начинающийся с _.
Изменить стандартный ID можно через следующую опцию:
db.put({
_id: 'id' + nanoid(),
…
})Можно сгенерировать уникальный ID прямо из терминала, вызвав npx nanoid.
Для этого в системе должна быть только Node.js. npx сама скачает Nano ID,
если его нет в системе.
$ npx nanoid
npx: installed 1 in 0.63s
LZfXLFzPPR4NNrgjlWDxnДлину генерируемых ID можно передать в аргументе --size (или -s):
$ npx nanoid --size 10
L3til0JS4zИзменить алфавит можно при помощи аргумента --alphabet (ли -a)
(в этом случае --size обязателен):
$ npx nanoid --alphabet abc --size 15
bccbcabaabaccabNano ID позволяет приводить сгенерированные строки к непрозрачным строкам в TypeScript. Например:
declare const userIdBrand: unique symbol
type UserId = string & { [userIdBrand]: true }
// Используйте явный параметр типа:
mockUser(nanoid<UserId>())
interface User {
id: UserId
name: string
}
const user: User = {
// Автоматически приводится к типу UserId:
id: nanoid(),
name: 'Alice'
}Nano ID был портирован на множество языков. Это полезно, чтобы сервер и клиент генерировали ID по одной схеме.
- C#
- C++
- Clojure и ClojureScript
- ColdFusion/CFML
- Crystal
- Dart и Flutter
- Elixir
- Gleam
- Go
- Haskell
- Haxe
- Janet
- Java
- Kotlin
- MySQL/MariaDB
- Nim
- Perl
- PHP
- Python со словарями
- Postgres: Rust-расширение и на чисто pgSQL
- R (со словарями)
- Ruby
- Rust
- Swift
- Unison
- V
- Zig
Для остальных сред можно использовать Nano ID для терминала.
- Калькулятор длины ID поможет подобрать оптимальную длину ID, в зависимости от частоты выдачи ID и нужной надёжности системы.
nanoid-dictionaryс популярными алфавитами дляcustomAlphabet.nanoid-goodгарантирует, что в случайном ID не будет матерных слов.
