UNPKG

13.6 kBMarkdownView Raw
1# Nano ID
2
3<img src="https://ai.github.io/nanoid/logo.svg" align="right"
4 alt="Nano ID logo by Anton Lovchikov" width="180" height="94">
5
6A tiny, secure, URL-friendly, unique string ID generator for JavaScript.
7
8> “An amazing level of senseless perfectionism,
9> which is simply impossible not to respect.”
10
11* **Small.** 108 bytes (minified and gzipped). No dependencies.
12 [Size Limit] controls the size.
13* **Fast.** It is 40% faster than UUID.
14* **Safe.** It uses cryptographically strong random APIs.
15 Can be used in clusters.
16* **Compact.** It uses a larger alphabet than UUID (`A-Za-z0-9_-`).
17 So ID size was reduced from 36 to 21 symbols.
18* **Portable.** Nano ID was ported
19 to [14 programming languages](#other-programming-languages).
20
21```js
22import { nanoid } from 'nanoid'
23model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
24```
25
26Supports modern browsers, IE [with Babel], Node.js and React Native.
27
28[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/
29[with Babel]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/
30[Size Limit]: https://github.com/ai/size-limit
31
32<a href="https://evilmartians.com/?utm_source=nanoid">
33 <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg"
34 alt="Sponsored by Evil Martians" width="236" height="54">
35</a>
36
37## Table of Contents
38
39* [Comparison with UUID](#comparison-with-uuid)
40* [Benchmark](#benchmark)
41* [Tools](#tools)
42* [Security](#security)
43* [Usage](#usage)
44 * [JS](#js)
45 * [IE](#ie)
46 * [React](#react)
47 * [Create React App](#create-react-app)
48 * [React Native](#react-native)
49 * [Expo](#expo)
50 * [PouchDB and CouchDB](#pouchdb-and-couchdb)
51 * [Mongoose](#mongoose)
52 * [ES Modules](#es-modules)
53 * [Web Workers](#web-workers)
54 * [CLI](#cli)
55 * [Other Programming Languages](#other-programming-languages)
56* [API](#api)
57 * [Async](#async)
58 * [Non-Secure](#non-secure)
59 * [Custom Alphabet or Size](#custom-alphabet-or-size)
60 * [Custom Random Bytes Generator](#custom-random-bytes-generator)
61
62
63## Comparison with UUID
64
65Nano ID is quite comparable to UUID v4 (random-based).
66It has a similar number of random bits in the ID
67(126 in Nano ID and 122 in UUID), so it has a similar collision probability:
68
69> For there to be a one in a billion chance of duplication,
70> 103 trillion version 4 IDs must be generated.
71
72There are three main differences between Nano ID and UUID v4:
73
741. Nano ID uses a bigger alphabet, so a similar number of random bits
75 are packed in just 21 symbols instead of 36.
762. Nano ID code is 3 times less than `uuid/v4` package:
77 108 bytes instead of 345.
783. Because of memory allocation tricks, Nano ID is 16% faster than UUID.
79
80
81## Benchmark
82
83```rust
84$ ./test/benchmark
85nanoid 655,798 ops/sec
86customAlphabet 635,421 ops/sec
87uid.sync 375,816 ops/sec
88uuid v4 396,756 ops/sec
89secure-random-string 366,434 ops/sec
90cuid 183,998 ops/sec
91shortid 59,343 ops/sec
92
93Async:
94async nanoid 101,966 ops/sec
95async customAlphabet 102,471 ops/sec
96async secure-random-string 97,206 ops/sec
97uid 91,291 ops/sec
98
99Non-secure:
100non-secure nanoid 2,754,423 ops/sec
101rndm 2,437,262 ops/sec
102```
103
104Test configuration: Dell XPS 2-in-a 7390, Fedora 32, Node.js 13.11.
105
106
107## Tools
108
109* [ID size calculator] shows collision probability when adjusting
110 the ID alphabet or size.
111* [`nanoid-dictionary`] with popular alphabets to use with `customAlphabet`.
112* [`nanoid-good`] to be sure that your ID doesn’t contain any obscene words.
113
114[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
115[ID size calculator]: https://zelark.github.io/nano-id-cc/
116[`nanoid-good`]: https://github.com/y-gagar1n/nanoid-good
117
118
119## Security
120
121*See a good article about random generators theory:
122[Secure random values (in Node.js)]*
123
124* **Unpredictability.** Instead of using the unsafe `Math.random()`, Nano ID
125 uses the `crypto` module in Node.js and the Web Crypto API in browsers.
126 These modules use unpredictable hardware random generator.
127* **Uniformity.** `random % alphabet` is a popular mistake to make when coding
128 an ID generator. The distribution will not be even; there will be a lower
129 chance for some symbols to appear compared to others. So, it will reduce
130 the number of tries when brute-forcing. Nano ID uses a [better algorithm]
131 and is tested for uniformity.
132
133 <img src="img/distribution.png" alt="Nano ID uniformity"
134 width="340" height="135">
135
136* **Vulnerabilities:** to report a security vulnerability, please use
137 the [Tidelift security contact](https://tidelift.com/security).
138 Tidelift will coordinate the fix and disclosure.
139
140[Secure random values (in Node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba
141[better algorithm]: https://github.com/ai/nanoid/blob/master/index.js
142
143
144## Usage
145
146### JS
147
148The main module uses URL-friendly symbols (`A-Za-z0-9_-`) and returns an ID
149with 21 characters (to have a collision probability similar to UUID v4).
150
151```js
152import { nanoid } from 'nanoid'
153model.id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
154```
155
156If you want to reduce the ID size (and increase collisions probability),
157you can pass the size as an argument.
158
159```js
160nanoid(10) //=> "IRFa-VaY2b"
161```
162
163Don’t forget to check the safety of your ID size
164in our [ID collision probability] calculator.
165
166You can also use a [custom alphabet](#custom-alphabet-or-size)
167or a [random generator](#custom-random-bytes-generator).
168
169[ID collision probability]: https://zelark.github.io/nano-id-cc/
170
171
172### IE
173
174If you support IE, you need to [transpile `node_modules`] by Babel
175and add `crypto` alias:
176
177```js
178if (!window.crypto) {
179 window.crypto = window.msCrypto
180}
181
182import { nanoid } from 'nanoid'
183```
184
185[transpile `node_modules`]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/
186
187
188### React
189
190**Do not** call `nanoid` in the `key` prop. In React, `key` should be consistent
191among renders.
192
193This is the bad example:
194
195```jsx
196<Item key={nanoid()} /> /* DON’T DO IT */
197```
198
199This is the good example (`id` will be generated only once):
200
201```jsx
202const Element = () => {
203 const [id] = React.useState(nanoid)
204 return <Item key={id} />
205}
206```
207
208If you want to use Nano ID in the `id` prop, you must set some string prefix
209(it is invalid for the HTML ID to start with a number).
210
211```jsx
212<input id={'id' + this.id} type="text"/>
213```
214
215
216### Create React App
217
218Create React App has [a problem](https://github.com/ai/nanoid/issues/205)
219with ES modules packages.
220
221```
222TypeError: (0 , _nanoid.nanoid) is not a function
223```
224
225If you have an error above, here is temporary fix:
226
2271. Use Nano ID 2 instead of 3: `npm i nanoid@^2.0.0`.
2282. Vote for
229 [pull request](https://github.com/facebook/create-react-app/pull/8768),
230 that fix dual packages support.
231
232
233### React Native
234
235React Native does not have built-in random generator.
236
2371. Check [`react-native-get-random-values`] docs and install it.
2382. Import it before Nano ID.
239
240```js
241import 'react-native-get-random-values'
242import { nanoid } from 'nanoid'
243```
244
245For Expo framework see the next section.
246
247[`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values
248
249
250### Expo
251
252If you use Expo in React Native, you need a different workaround.
253
2541. Install [`expo-random`](https://www.npmjs.com/package/expo-random).
2552. Use `nanoid/async` instead of `nanoid`.
2563. Import `index.native.js` file directly.
257
258```js
259import { nanoid } from 'nanoid/async/index.native'
260
261async function createUser () {
262 user.id = await nanoid()
263}
264```
265
266[`expo-random`]: https://www.npmjs.com/package/expo-random
267
268
269### PouchDB and CouchDB
270
271In PouchDB and CouchDB, IDs can’t start with an underscore `_`.
272A prefix is required to prevent this issue, as Nano ID might use a `_`
273at the start of the ID by default.
274
275Override the default ID with the following option:
276
277```js
278db.put({
279 _id: 'id' + nanoid(),
280
281})
282```
283
284
285### Mongoose
286
287```js
288const mySchema = new Schema({
289 _id: {
290 type: String,
291 default: () => nanoid()
292 }
293})
294```
295
296
297### ES Modules
298
299Nano ID provides ES modules. You do not need to do anything to use Nano ID
300as ESM in webpack, Rollup, Parcel, or Node.js.
301
302```js
303import { nanoid } from 'nanoid'
304```
305
306For quick hacks, you can load Nano ID from CDN. Special minified
307`nanoid.js` module is available on jsDelivr.
308
309Though, it is not recommended to be used in production
310because of the lower loading performance.
311
312```js
313import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'
314```
315
316
317### Web Workers
318
319Web Workers do not have access to a secure random generator.
320
321Security is important in IDs when IDs should be unpredictable.
322For instance, in "access by URL" link generation.
323If you do not need unpredictable IDs, but you need to use Web Workers,
324you can use the non‑secure ID generator.
325
326```js
327import { nanoid } from 'nanoid/non-secure'
328nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
329```
330
331Note: non-secure IDs are more prone to collision attacks.
332
333
334### CLI
335
336You can get unique ID in terminal by calling `npx nanoid`. You need only
337Node.js in the system. You do not need Nano ID to be installed anywhere.
338
339```sh
340$ npx nanoid
341npx: installed 1 in 0.63s
342LZfXLFzPPR4NNrgjlWDxn
343```
344
345If you want to change alphabet or ID size, you should use [`nanoid-cli`].
346
347[`nanoid-cli`]: https://github.com/twhitbeck/nanoid-cli
348
349
350### Other Programming Languages
351
352Nano ID was ported to many languages. You can use these ports to have
353the same ID generator on the client and server side.
354
355* [C#](https://github.com/codeyu/nanoid-net)
356* [C++](https://github.com/mcmikecreations/nanoid_cpp)
357* [Clojure and ClojureScript](https://github.com/zelark/nano-id)
358* [Crystal](https://github.com/mamantoha/nanoid.cr)
359* [Dart](https://github.com/pd4d10/nanoid-dart)
360* [Deno](https://github.com/ianfabs/nanoid)
361* [Go](https://github.com/matoous/go-nanoid)
362* [Elixir](https://github.com/railsmechanic/nanoid)
363* [Haskell](https://github.com/4e6/nanoid-hs)
364* [Janet](https://sr.ht/~statianzo/janet-nanoid/)
365* [Java](https://github.com/aventrix/jnanoid)
366* [Nim](https://github.com/icyphox/nanoid.nim)
367* [PHP](https://github.com/hidehalo/nanoid-php)
368* [Python](https://github.com/puyuan/py-nanoid)
369 with [dictionaries](https://pypi.org/project/nanoid-dictionary)
370* [Ruby](https://github.com/radeno/nanoid.rb)
371* [Rust](https://github.com/nikolay-govorov/nanoid)
372* [Swift](https://github.com/antiflasher/NanoID)
373
374Also, [CLI] is available to generate IDs from a command line.
375
376[CLI]: #cli
377
378
379## API
380
381### Async
382
383To generate hardware random bytes, CPU collects electromagnetic noise.
384In the synchronous API during the noise collection, the CPU is busy and
385cannot do anything useful in parallel.
386
387Using the asynchronous API of Nano ID, another code can run during
388the entropy collection.
389
390```js
391import { nanoid } from 'nanoid/async'
392
393async function createUser () {
394 user.id = await nanoid()
395}
396```
397
398Unfortunately, you will lose Web Crypto API advantages in a browser
399if you the asynchronous API. So, currently, in the browser, you are limited
400with either security or asynchronous behavior.
401
402
403### Non-Secure
404
405By default, Nano ID uses hardware random bytes generation for security
406and low collision probability. If you are not so concerned with security
407and more concerned with performance, you can use the faster non-secure generator.
408
409```js
410import { nanoid } from 'nanoid/non-secure'
411const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"
412```
413
414Note: your IDs will be more predictable and prone to collision attacks.
415
416
417### Custom Alphabet or Size
418
419`customAlphabet` allows you to create `nanoid` with your own alphabet
420and ID size.
421
422```js
423import { customAlphabet } from 'nanoid'
424const nanoid = customAlphabet('1234567890abcdef', 10)
425model.id = nanoid() //=> "4f90d13a42"
426```
427
428Check the safety of your custom alphabet and ID size in our
429[ID collision probability] calculator. For more alphabets, check out the options
430in [`nanoid-dictionary`].
431
432Alphabet must contain 256 symbols or less.
433Otherwise, the security of the internal generator algorithm is not guaranteed.
434
435Customizable asynchronous and non-secure APIs are also available:
436
437```js
438import { customAlphabet } from 'nanoid/async'
439const nanoid = customAlphabet('1234567890abcdef', 10)
440async function createUser () {
441 user.id = await nanoid()
442}
443```
444
445```js
446import { customAlphabet } from 'nanoid/non-secure'
447const nanoid = customAlphabet('1234567890abcdef', 10)
448user.id = nanoid()
449```
450
451[ID collision probability]: https://alex7kom.github.io/nano-nanoid-cc/
452[`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary
453
454
455### Custom Random Bytes Generator
456
457`customRandom` allows you to create a `nanoid` and replace alphabet
458and the default random bytes generator.
459
460In this example, a seed-based generator is used:
461
462```js
463import { customRandom } from 'nanoid'
464
465const rng = seedrandom(seed)
466const nanoid = customRandom('abcdef', 10, size => {
467 return (new Uint8Array(size)).map(() => 256 * rng())
468})
469
470nanoid() //=> "fbaefaadeb"
471```
472
473`random` callback must accept the array size and return an array
474with random numbers.
475
476If you want to use the same URL-friendly symbols with `customRandom`,
477you can get the default alphabet using the `urlAlphabet`.
478
479```js
480const { customRandom, urlAlphabet } = require('nanoid')
481const nanoid = customRandom(urlAlphabet, 10, random)
482```
483
484Asynchronous and non-secure APIs are not available for `customRandom`.