| # Nano ID |
| |
| <img src="https://ai.github.io/nanoid/logo.svg" align="right" |
| alt="Nano ID logo by Anton Lovchikov" width="180" height="94"> |
| |
| A tiny, secure, URL-friendly, unique string ID generator for JavaScript. |
| |
| > “An amazing level of senseless perfectionism, |
| > which is simply impossible not to respect.” |
| |
| * **Small.** 108 bytes (minified and gzipped). No dependencies. |
| [Size Limit] controls the size. |
| * **Fast.** It is 60% faster than UUID. |
| * **Safe.** It uses cryptographically strong random APIs. |
| Can be used in clusters. |
| * **Compact.** It uses a larger alphabet than UUID (`A-Za-z0-9_-`). |
| So ID size was reduced from 36 to 21 symbols. |
| * **Portable.** Nano ID was ported |
| to [14 programming languages](#other-programming-languages). |
| |
| ```js |
| import { nanoid } from 'nanoid' |
| model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT" |
| ``` |
| |
| Supports modern browsers, IE [with Babel], Node.js and React Native. |
| |
| [online tool]: https://gitpod.io/#https://github.com/ai/nanoid/ |
| [with 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 |
| |
| <a href="https://evilmartians.com/?utm_source=nanoid"> |
| <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" |
| alt="Sponsored by Evil Martians" width="236" height="54"> |
| </a> |
| |
| ## Table of Contents |
| |
| * [Comparison with UUID](#comparison-with-uuid) |
| * [Benchmark](#benchmark) |
| * [Tools](#tools) |
| * [Security](#security) |
| * [Usage](#usage) |
| * [JS](#js) |
| * [IE](#ie) |
| * [React](#react) |
| * [Create React App](#create-react-app) |
| * [React Native](#react-native) |
| * [Rollup](#rollup) |
| * [Expo](#expo) |
| * [PouchDB and CouchDB](#pouchdb-and-couchdb) |
| * [Mongoose](#mongoose) |
| * [ES Modules](#es-modules) |
| * [Web Workers](#web-workers) |
| * [CLI](#cli) |
| * [Other Programming Languages](#other-programming-languages) |
| * [API](#api) |
| * [Async](#async) |
| * [Non-Secure](#non-secure) |
| * [Custom Alphabet or Size](#custom-alphabet-or-size) |
| * [Custom Random Bytes Generator](#custom-random-bytes-generator) |
| |
| |
| ## Comparison with UUID |
| |
| Nano ID is quite comparable to UUID v4 (random-based). |
| It has a similar number of random bits in the ID |
| (126 in Nano ID and 122 in UUID), so it has a similar collision probability: |
| |
| > For there to be a one in a billion chance of duplication, |
| > 103 trillion version 4 IDs must be generated. |
| |
| There are three main differences between Nano ID and UUID v4: |
| |
| 1. Nano ID uses a bigger alphabet, so a similar number of random bits |
| are packed in just 21 symbols instead of 36. |
| 2. Nano ID code is **4.5 times less** than `uuid/v4` package: |
| 108 bytes instead of 483. |
| 3. Because of memory allocation tricks, Nano ID is **60%** faster than UUID. |
| |
| |
| ## Benchmark |
| |
| ```rust |
| $ node ./test/benchmark.js |
| nanoid 2,280,683 ops/sec |
| customAlphabet 1,851,117 ops/sec |
| uuid v4 1,348,425 ops/sec |
| uid.sync 313,306 ops/sec |
| secure-random-string 294,161 ops/sec |
| cuid 158,988 ops/sec |
| shortid 37,222 ops/sec |
| |
| Async: |
| async nanoid 95,500 ops/sec |
| async customAlphabet 93,800 ops/sec |
| async secure-random-string 90,316 ops/sec |
| uid 85,583 ops/sec |
| |
| Non-secure: |
| non-secure nanoid 2,641,654 ops/sec |
| rndm 2,447,086 ops/sec |
| ``` |
| |
| Test configuration: Dell XPS 2-in-1 7390, Fedora 32, Node.js 15.1. |
| |
| |
| ## Tools |
| |
| * [ID size calculator] shows collision probability when adjusting |
| the ID alphabet or size. |
| * [`nanoid-dictionary`] with popular alphabets to use with `customAlphabet`. |
| * [`nanoid-good`] to be sure that your ID doesn’t contain any obscene words. |
| |
| [`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary |
| [ID size calculator]: https://zelark.github.io/nano-id-cc/ |
| [`nanoid-good`]: https://github.com/y-gagar1n/nanoid-good |
| |
| |
| ## Security |
| |
| *See a good article about random generators theory: |
| [Secure random values (in Node.js)]* |
| |
| * **Unpredictability.** Instead of using the unsafe `Math.random()`, Nano ID |
| uses the `crypto` module in Node.js and the Web Crypto API in browsers. |
| These modules use unpredictable hardware random generator. |
| * **Uniformity.** `random % alphabet` is a popular mistake to make when coding |
| an ID generator. The distribution will not be even; there will be a lower |
| chance for some symbols to appear compared to others. So, it will reduce |
| the number of tries when brute-forcing. Nano ID uses a [better algorithm] |
| and is tested for uniformity. |
| |
| <img src="img/distribution.png" alt="Nano ID uniformity" |
| width="340" height="135"> |
| |
| * **Vulnerabilities:** to report a security vulnerability, please use |
| the [Tidelift security contact](https://tidelift.com/security). |
| Tidelift will coordinate the fix and disclosure. |
| |
| [Secure random values (in Node.js)]: https://gist.github.com/joepie91/7105003c3b26e65efcea63f3db82dfba |
| [better algorithm]: https://github.com/ai/nanoid/blob/master/index.js |
| |
| |
| ## Usage |
| |
| ### JS |
| |
| The main module uses URL-friendly symbols (`A-Za-z0-9_-`) and returns an ID |
| with 21 characters (to have a collision probability similar to UUID v4). |
| |
| ```js |
| import { nanoid } from 'nanoid' |
| model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT" |
| ``` |
| |
| If you want to reduce the ID size (and increase collisions probability), |
| you can pass the size as an argument. |
| |
| ```js |
| nanoid(10) //=> "IRFa-VaY2b" |
| ``` |
| |
| Don’t forget to check the safety of your ID size |
| in our [ID collision probability] calculator. |
| |
| You can also use a [custom alphabet](#custom-alphabet-or-size) |
| or a [random generator](#custom-random-bytes-generator). |
| |
| [ID collision probability]: https://zelark.github.io/nano-id-cc/ |
| |
| |
| ### IE |
| |
| If you support IE, you need to [transpile `node_modules`] by Babel |
| and add `crypto` alias: |
| |
| ```js |
| // polyfills.js |
| if (!window.crypto) { |
| window.crypto = window.msCrypto |
| } |
| ``` |
| |
| ```js |
| import './polyfills.js' |
| import { nanoid } from 'nanoid' |
| ``` |
| |
| [transpile `node_modules`]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/ |
| |
| |
| ### React |
| |
| **Do not** call `nanoid` in the `key` prop. In React, `key` should be consistent |
| among renders. |
| |
| This is the bad example: |
| |
| ```jsx |
| <Item key={nanoid()} /> /* DON’T DO IT */ |
| ``` |
| |
| This is the good example (`id` will be generated only once): |
| |
| ```jsx |
| const Element = () => { |
| const [id] = React.useState(nanoid) |
| return <Item key={id} /> |
| } |
| ``` |
| |
| If you want to use Nano ID in the `id` prop, you must set some string prefix |
| (it is invalid for the HTML ID to start with a number). |
| |
| ```jsx |
| <input id={'id' + this.id} type="text"/> |
| ``` |
| |
| |
| ### Create React App |
| |
| Create React App has [a problem](https://github.com/ai/nanoid/issues/205) |
| with ES modules packages. |
| |
| ``` |
| TypeError: (0 , _nanoid.nanoid) is not a function |
| ``` |
| |
| [Pull request](https://github.com/facebook/create-react-app/pull/8768) was sent, |
| but it was still not released. |
| |
| Use Nano ID 2 `npm i nanoid@^2.0.0` until Create React App 4.0 release. |
| |
| |
| ### React Native |
| |
| React Native does not have built-in random generator. |
| |
| 1. Check [`react-native-get-random-values`] docs and install it. |
| 2. Import it before Nano ID. |
| |
| ```js |
| import 'react-native-get-random-values' |
| import { nanoid } from 'nanoid' |
| ``` |
| |
| For Expo framework see the next section. |
| |
| [`react-native-get-random-values`]: https://github.com/LinusU/react-native-get-random-values |
| |
| |
| ### Rollup |
| |
| For Rollup you will need [`@rollup/plugin-replace`] to replace |
| `process.env.NODE_ENV`: |
| |
| ```js |
| plugins: [ |
| replace({ |
| 'process.env.NODE_ENV': JSON.stringify(process.env.NODE) |
| }) |
| ] |
| ``` |
| |
| [`@rollup/plugin-replace`]: https://github.com/rollup/plugins/tree/master/packages/replace |
| |
| |
| ### Expo |
| |
| If you use Expo in React Native, you need a different workaround. |
| |
| 1. Install [`expo-random`](https://www.npmjs.com/package/expo-random). |
| 2. Use `nanoid/async` instead of `nanoid`. |
| 3. Import `index.native.js` file directly. |
| |
| ```js |
| import { nanoid } from 'nanoid/async/index.native' |
| |
| async function createUser () { |
| user.id = await nanoid() |
| } |
| ``` |
| |
| [`expo-random`]: https://www.npmjs.com/package/expo-random |
| |
| |
| ### PouchDB and CouchDB |
| |
| In PouchDB and CouchDB, IDs can’t start with an underscore `_`. |
| A prefix is required to prevent this issue, as Nano ID might use a `_` |
| at the start of the ID by default. |
| |
| Override the default ID with the following option: |
| |
| ```js |
| db.put({ |
| _id: 'id' + nanoid(), |
| … |
| }) |
| ``` |
| |
| |
| ### Mongoose |
| |
| ```js |
| const mySchema = new Schema({ |
| _id: { |
| type: String, |
| default: () => nanoid() |
| } |
| }) |
| ``` |
| |
| |
| ### ES Modules |
| |
| Nano ID provides ES modules. You do not need to do anything to use Nano ID |
| as ESM in webpack, Rollup, Parcel, or Node.js. |
| |
| ```js |
| import { nanoid } from 'nanoid' |
| ``` |
| |
| For quick hacks, you can load Nano ID from CDN. Special minified |
| `nanoid.js` module is available on jsDelivr. |
| |
| Though, it is not recommended to be used in production |
| because of the lower loading performance. |
| |
| ```js |
| import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js' |
| ``` |
| |
| |
| ### Web Workers |
| |
| Web Workers do not have access to a secure random generator. |
| |
| Security is important in IDs when IDs should be unpredictable. |
| For instance, in "access by URL" link generation. |
| If you do not need unpredictable IDs, but you need to use Web Workers, |
| you can use the non‑secure ID generator. |
| |
| ```js |
| import { nanoid } from 'nanoid/non-secure' |
| nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ" |
| ``` |
| |
| Note: non-secure IDs are more prone to collision attacks. |
| |
| |
| ### CLI |
| |
| You can get unique ID in terminal by calling `npx nanoid`. You need only |
| Node.js in the system. You do not need Nano ID to be installed anywhere. |
| |
| ```sh |
| $ npx nanoid |
| npx: installed 1 in 0.63s |
| LZfXLFzPPR4NNrgjlWDxn |
| ``` |
| |
| If you want to change alphabet or ID size, you should use [`nanoid-cli`]. |
| |
| [`nanoid-cli`]: https://github.com/twhitbeck/nanoid-cli |
| |
| |
| ### Other Programming Languages |
| |
| Nano ID was ported to many languages. You can use these ports to have |
| the same ID generator on the client and server side. |
| |
| * [C#](https://github.com/codeyu/nanoid-net) |
| * [C++](https://github.com/mcmikecreations/nanoid_cpp) |
| * [Clojure and ClojureScript](https://github.com/zelark/nano-id) |
| * [Crystal](https://github.com/mamantoha/nanoid.cr) |
| * [Dart](https://github.com/pd4d10/nanoid-dart) |
| * [Deno](https://github.com/ianfabs/nanoid) |
| * [Go](https://github.com/matoous/go-nanoid) |
| * [Elixir](https://github.com/railsmechanic/nanoid) |
| * [Haskell](https://github.com/4e6/nanoid-hs) |
| * [Janet](https://sr.ht/~statianzo/janet-nanoid/) |
| * [Java](https://github.com/aventrix/jnanoid) |
| * [Nim](https://github.com/icyphox/nanoid.nim) |
| * [PHP](https://github.com/hidehalo/nanoid-php) |
| * [Python](https://github.com/puyuan/py-nanoid) |
| with [dictionaries](https://pypi.org/project/nanoid-dictionary) |
| * [Ruby](https://github.com/radeno/nanoid.rb) |
| * [Rust](https://github.com/nikolay-govorov/nanoid) |
| * [Swift](https://github.com/antiflasher/NanoID) |
| |
| Also, [CLI] is available to generate IDs from a command line. |
| |
| [CLI]: #cli |
| |
| |
| ## API |
| |
| ### Async |
| |
| To generate hardware random bytes, CPU collects electromagnetic noise. |
| In the synchronous API during the noise collection, the CPU is busy and |
| cannot do anything useful in parallel. |
| |
| Using the asynchronous API of Nano ID, another code can run during |
| the entropy collection. |
| |
| ```js |
| import { nanoid } from 'nanoid/async' |
| |
| async function createUser () { |
| user.id = await nanoid() |
| } |
| ``` |
| |
| Unfortunately, you will lose Web Crypto API advantages in a browser |
| if you use the asynchronous API. So, currently, in the browser, you are limited |
| with either security or asynchronous behavior. |
| |
| |
| ### Non-Secure |
| |
| By default, Nano ID uses hardware random bytes generation for security |
| and low collision probability. If you are not so concerned with security |
| and more concerned with performance, you can use the faster non-secure generator. |
| |
| ```js |
| import { nanoid } from 'nanoid/non-secure' |
| const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ" |
| ``` |
| |
| Note: your IDs will be more predictable and prone to collision attacks. |
| |
| |
| ### Custom Alphabet or Size |
| |
| `customAlphabet` allows you to create `nanoid` with your own alphabet |
| and ID size. |
| |
| ```js |
| import { customAlphabet } from 'nanoid' |
| const nanoid = customAlphabet('1234567890abcdef', 10) |
| model.id = nanoid() //=> "4f90d13a42" |
| ``` |
| |
| Check the safety of your custom alphabet and ID size in our |
| [ID collision probability] calculator. For more alphabets, check out the options |
| in [`nanoid-dictionary`]. |
| |
| Alphabet must contain 256 symbols or less. |
| Otherwise, the security of the internal generator algorithm is not guaranteed. |
| |
| Customizable asynchronous and non-secure APIs are also available: |
| |
| ```js |
| import { customAlphabet } from 'nanoid/async' |
| const nanoid = customAlphabet('1234567890abcdef', 10) |
| async function createUser () { |
| user.id = await nanoid() |
| } |
| ``` |
| |
| ```js |
| import { customAlphabet } from 'nanoid/non-secure' |
| const nanoid = customAlphabet('1234567890abcdef', 10) |
| user.id = nanoid() |
| ``` |
| |
| [ID collision probability]: https://alex7kom.github.io/nano-nanoid-cc/ |
| [`nanoid-dictionary`]: https://github.com/CyberAP/nanoid-dictionary |
| |
| |
| ### Custom Random Bytes Generator |
| |
| `customRandom` allows you to create a `nanoid` and replace alphabet |
| and the default random bytes generator. |
| |
| In this example, a seed-based generator is used: |
| |
| ```js |
| import { customRandom } from 'nanoid' |
| |
| const rng = seedrandom(seed) |
| const nanoid = customRandom('abcdef', 10, size => { |
| return (new Uint8Array(size)).map(() => 256 * rng()) |
| }) |
| |
| nanoid() //=> "fbaefaadeb" |
| ``` |
| |
| `random` callback must accept the array size and return an array |
| with random numbers. |
| |
| If you want to use the same URL-friendly symbols with `customRandom`, |
| you can get the default alphabet using the `urlAlphabet`. |
| |
| ```js |
| const { customRandom, urlAlphabet } = require('nanoid') |
| const nanoid = customRandom(urlAlphabet, 10, random) |
| ``` |
| |
| Asynchronous and non-secure APIs are not available for `customRandom`. |