# Nano ID
[English](./README.md) | [日本語](./README.ja.md) | **Русский** | [简体中文](./README.zh-CN.md) | [Bahasa Indonesia](./README.id-ID.md) | [한국어](./README.ko.md) | [العربية](./README.ar.md)
Генератор уникальных ID для JavaScript — лёгкий, безопасный,
ID можно применять в URL.
> «Поразительный уровень бессмысленного перфекционизма,
> который просто невозможно не уважать»
- **Лёгкий.** 118 байт (после минификации и Brotli). Без зависимостей.
[Size Limit] следит за размером.
- **Безопасный.** Использует аппаратный генератор случайных чисел.
Можно использовать в кластерах машин.
- **Короткие ID.** Используется больший алфавит, чем у UUID (`A-Za-z0-9_-`).
Поэтому длина ID уменьшена с 36 до 21 символа.
- **Работает везде.** Nano ID уже портировали
на [20 языков программирования](#другие-языки-программирования).
```js
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```
Поддерживает современные браузеры, IE ([с Babel]), Node.js и React Native.
[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/
[с babel]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/
[size limit]: https://github.com/ai/size-limit
---
Сделано в Злых марсианах, продуктовом консалтинге для инструментов разработки.
---
## Оглавление
- [Оглавление](#оглавление)
- [Сравнение с UUID](#сравнение-с-uuid)
- [Сравнение производительности](#сравнение-производительности)
- [Безопасность](#безопасность)
- [Подключение](#подключение)
- [ESM](#esm)
- [CommonJS](#commonjs)
- [JSR](#jsr)
- [CDN](#cdn)
- [API](#api)
- [Блокирующий](#блокирующий)
- [Небезопасный](#небезопасный)
- [Смена алфавита или длины](#смена-алфавита-или-длины)
- [Смена генератора случайных чисел](#смена-генератора-случайных-чисел)
- [Руководство](#руководство)
- [React](#react)
- [React Native](#react-native)
- [PouchDB и CouchDB](#pouchdb-и-couchdb)
- [Терминал](#терминал)
- [TypeScript](#typescript)
- [Другие языки программирования](#другие-языки-программирования)
- [Инструменты](#инструменты)
## Сравнение с UUID
Nano ID похож на UUID v4 (случайный).
У них сравнимое число битов случайности в ID (126 у Nano ID против 122 у UUID),
поэтому они обладают похожей вероятностью возникновения коллизий
(повторной генерации ранее выданных ID):
> Чтобы вероятность повтора приблизилась к 1 на миллиард,
> нужно сгенерировать 103 триллиона ID.
Но между ними есть 2 важных отличия:
1. Nano ID использует более широкий алфавит, и сравнимое количество
битов случайности будут упакованы в более короткую строку
(21 символ, против 36 у UUID).
2. Код Nano ID **в 4 раз меньше**, чем у `uuid/v4` — 118 байт против 423.
## Сравнение производительности
```rust
$ 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](https://tidelift.com/security).
Они проконтролируют исправление и проинформируют пользователей.
[secure random values (in node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba
[более совершенный алгоритм]: https://github.com/ai/nanoid/blob/main/index.js
[в исходниках]: https://github.com/ai/nanoid/blob/main/index.js
## Подключение
### ESM
Nano ID 5 работает с ESM-проектами (`import`) в тестах или скриптах для Node.js.
```bash
npm install nanoid
```
### CommonJS
На проектах с CommonJS вы можете использовать:
- `require()` будет работать в последней версия Node.js 22.12 (из коробки)
или Node.js 20 (с флагом `--experimental-require-module`).
- В более старых версиях Node.js можно использовать динамический импорт:
```js
let nanoid
module.exports.createID = async () => {
if (!nanoid) ({ nanoid } = await import('nanoid'))
return nanoid() // => "V1StGXR8_Z5jdHi6B-myT"
}
```
- Или можно просто взять Nano ID 3.x (мы его всё ещё поддерживаем):
```bash
npm install nanoid@3
```
### JSR
[JSR](https://jsr.io) это замена npm с открытым управлением
и активной разработкой (в отличие от npm).
```bash
npx jsr add @sitnik/nanoid
```
Вы можете использовать пакет с JSR в Node.js, Deno, Bun.
```js
// Replace `nanoid` to `@sitnik/nanoid` in all imports
import { nanoid } from '@sitnik/nanoid'
```
Для Deno установите через `deno add jsr:@sitnik/nanoid`
или импортируйте `jsr:@sitnik/nanoid`.
### CDN
Для быстрого прототипирования вы можете подключить Nano ID с CDN без установки.
Не используйте этот способ на реальном сайте, так как он сильно бьёт
по скорости загрузки сайта.
```js
import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
```
## API
Nano ID разделён на два модуля: стандартный и небезопасный.
По умолчанию используются символы, безопасные для URL (`A-Za-z0-9_-`).
Длина ID по умолчанию — 21 символ
(чтобы вероятность коллизий была соизмеримой с UUID v4).
### Блокирующий
Безопасный и простой в использовании способ использования Nano ID.
Из-за особенностей работы генератора случайных чисел при использовании этого
способа ЦПУ может иногда простаивать без работы.
```js
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
```
Функция также принимает необязательный аргумент, задающий длину ID:
```js
nanoid(10) //=> "IRFa-VaY2b"
```
При изменении размера, всегда проверяйте риски
в нашем [калькуляторе коллизий](https://zelark.github.io/nano-id-cc/).
### Небезопасный
По умолчанию, Nano ID использует аппаратный генератор случайных чисел для
получения непредсказуемых ID и минимизации риска возникновения коллизий
(повторной генерации ранее выданных ID). Но если вам не требуется устойчивость
к подбору ID, то вы можете перейти на небезопасный генератор — это полезно
там, где нет доступа к API аппаратного генератора случайных чисел.
```js
import { nanoid } from 'nanoid/non-secure'
const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
```
Но учтите, что предсказуемость ID может быть использована для атаки на систему.
### Смена алфавита или длины
Функция `customAlphabet` позволяет создать свою функцию `nanoid`
с нужным вам алфавитом и длиной ID.
```js
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
user.id = nanoid() //=> "4f90d13a42"
```
```js
import { customAlphabet } from 'nanoid/non-secure'
const nanoid = customAlphabet('1234567890abcdef', 10)
user.id = nanoid()
```
Не забудьте проверить риски коллизии вашего алфавита и длины
[на нашем калькуляторе]. [`nanoid-dictionary`] содержит много популярных
примеров альтернативных алфавитов.
Алфавит должен содержать ≤256 символов. Иначе мы не сможем гарантировать
непредсказуемость ID.
Длину ID можно менять не только в `customAlphabet()`, но и при вызове
генератора, который она вернёт:
```js
import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid(5) //=> "f01a2"
```
[на нашем калькуляторе]: https://zelark.github.io/nano-id-cc/
[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
### Смена генератора случайных чисел
Функция `customRandom` позволяет создать свою функцию `nanoid` со своими
генераторами случайных чисел, алфавитом и длинной ID.
Например, можно использовать генератор c seed для повторяемости тестов.
```js
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`.
```js
const { customRandom, urlAlphabet } = require('nanoid')
const nanoid = customRandom(urlAlphabet, 10, random)
```
## Руководство
### React
Не используйте Nano ID для генерации свойства `key` в JSX. При каждом рендере
`key` будет разный, что плохо скажется на производительности.
```jsx
function Todos({ todos }) {
return (