English | 日本語 | Русский | 简体中文 | Bahasa Indonesia | 한국어 | العربية
Генератор уникальных ID для JavaScript — лёгкий, безопасный, ID можно применять в URL.
«Поразительный уровень бессмысленного перфекционизма, который просто невозможно не уважать»
- Лёгкий. 127 байт (после минификации и Brotli). Без зависимостей. Size Limit следит за размером.
- Быстрый. На 50% быстрее нативного
crypto.randomUUID(). - Безопасный. Использует аппаратный генератор случайных чисел. Можно использовать в кластерах машин.
- Короткие 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.
Nano ID сделан в Злых марсианах, американском консалтинге по дизайну и разработке для стартапов в области инструментов разработки, ИИ и кибербезопасности.
- Оглавление
- Сравнение с UUID
- Сравнение производительности
- Безопасность
- Подключение
- API
- Руководство
- Инструменты
Nano ID похож на UUID v4 (случайный). У них сравнимое число битов случайности в ID (126 у Nano ID против 122 у UUID), поэтому они обладают похожей вероятностью возникновения коллизий (повторной генерации ранее выданных ID):
Чтобы вероятность повтора приблизилась к 1 на миллиард, нужно сгенерировать 103 триллиона ID.
Но между ними есть 2 важных отличия:
- Nano ID использует более широкий алфавит, и сравнимое количество битов случайности будут упакованы в более короткую строку (21 символ, против 36 у UUID).
- Nano ID быстрее, чем
crypto.randomUUIDиuuid/v4.
$ node ./test/benchmark.js
nope-id 20,386,830 ops/sec
nanoid 20,434,827 ops/sec
customAlphabet 20,544,476 ops/sec
crypto.randomUUID 12,865,759 ops/sec
uuid v4 7,930,104 ops/sec
@napi-rs/uuid 5,573,171 ops/sec
uid/secure 6,308,267 ops/sec
@lukeed/uuid 5,278,597 ops/sec
nanoid for browser 311,497 ops/sec
secure-random-string 301,667 ops/sec
uid-safe.sync 297,815 ops/sec
Non-secure:
uid 20,286,757 ops/sec
nanoid/non-secure 2,397,594 ops/sec
rndm 2,445,462 ops/secСм. также хорошую статью о теориях генераторов случайных чисел: 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. Они проконтролируют исправление и проинформируют пользователей.
npm install nanoidJSR это замена 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";По умолчанию используются символы, безопасные для URL (A-Za-z0-9_-).
Длина ID по умолчанию — 21 символ
(чтобы вероятность коллизий была соизмеримой с UUID v4).
import { nanoid } from "nanoid";
model.id = nanoid(); //=> "V1StGXR8_Z5jdHi6B-myT"Функция также принимает необязательный аргумент, задающий длину ID:
nanoid(10); //=> "IRFa-VaY2b"При изменении размера, всегда проверяйте риски в нашем калькуляторе коллизий.
Функция 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 использует аппаратный генератор случайных чисел для получения непредсказуемых ID и минимизации риска возникновения коллизий (повторной генерации ранее выданных ID). Но если вам не требуется устойчивость к подбору ID, то вы можете перейти на небезопасный генератор — это полезно там, где нет доступа к API аппаратного генератора случайных чисел.
import { nanoid } from "nanoid/non-secure";
const id = nanoid(); //=> "Uakgb_J5m9g-0JDMbcJqLJ"Но учтите, что предсказуемость ID может быть использована для атаки на систему. Кроме того, небезопасная версия работает медленнее безопасной — используйте её, только если без неё не обойтись.
Не используйте 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 не будет матерных слов.
