Giter Club home page Giter Club logo

nanoid's Introduction

Nano ID

Nano ID logo by Anton Lovchikov

English | Русский | 简体中文 | Bahasa Indonesia

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. 116 bytes (minified and brotlied). No dependencies. Size Limit controls the size.
  • Safe. It uses hardware random generator. Can be used in clusters.
  • Short IDs. 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 over 20 programming languages.
import { nanoid } from 'nanoid'
model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"

  Made in Evil Martians, product consulting for developer tools.


Table of Contents

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 two 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 times smaller than uuid/v4 package: 130 bytes instead of 423.

Benchmark

$ node ./test/benchmark.js
crypto.randomUUID         28,398,328 ops/sec
uuid v4                   10,254,199 ops/sec
@napi-rs/uuid             15,110,625 ops/sec
uid/secure                10,388,842 ops/sec
@lukeed/uuid               8,914,507 ops/sec
nanoid                     7,484,029 ops/sec
customAlphabet             4,867,017 ops/sec
nanoid for browser           609,426 ops/sec
secure-random-string         539,080 ops/sec
uid-safe.sync                533,944 ops/sec
shortid                       59,609 ops/sec

Non-secure:
uid                       95,579,977 ops/sec
nanoid/non-secure          3,999,766 ops/sec
rndm                       3,981,914 ops/sec

Test configuration: Framework 13 7840U, Fedora 39, Node.js 21.6.

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.

    Nano ID uniformity

  • Well-documented: all Nano ID hacks are documented. See comments in the source.

  • Vulnerabilities: to report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure.

Install

npm install nanoid

Nano ID 5 works only with ESM projects, in tests or Node.js scripts. For CommonJS you need to use Node.js 22 with --experimental-require-module:

node --experimental-require-module app.js

Or you can use Nano ID 3.x (we still support it):

npm install nanoid@3

For quick hacks, you can load Nano ID from CDN. Though, it is not recommended to be used in production because of the lower loading performance.

import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'

API

Nano ID has 2 APIs: normal and non-secure.

By default, Nano ID uses URL-friendly symbols (A-Za-z0-9_-) and returns an ID with 21 characters (to have a collision probability similar to UUID v4).

Blocking

The safe and easiest way to use Nano ID.

In rare cases could block CPU from other work while noise collection for hardware random generator.

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.

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 or a random generator.

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, you can use it for environments without hardware random generators.

import { nanoid } from 'nanoid/non-secure'
const id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqLJ"

Custom Alphabet or Size

customAlphabet returns a function that allows you to create nanoid with your own alphabet and ID size.

import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid() //=> "4f90d13a42"
import { customAlphabet } from 'nanoid/non-secure'
const nanoid = customAlphabet('1234567890abcdef', 10)
user.id = nanoid()

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.

In addition to setting a default size, you can change the ID size when calling the function:

import { customAlphabet } from 'nanoid'
const nanoid = customAlphabet('1234567890abcdef', 10)
model.id = nanoid(5) //=> "f01a2"

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:

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.

const { customRandom, urlAlphabet } = require('nanoid')
const nanoid = customRandom(urlAlphabet, 10, random)

Note, that between Nano ID versions we may change random generator call sequence. If you are using seed-based generators, we do not guarantee the same result.

Usage

React

There’s no correct way to use Nano ID for React key prop since it should be consistent among renders.

function Todos({todos}) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={nanoid()}> /* DON’T DO IT */
          {todo.text}
        </li>
      ))}
    </ul>
  )
}

You should rather try to reach for stable ID inside your list item.

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
)

In case you don’t have stable IDs you'd rather use index as key instead of nanoid():

const todoItems = todos.map((text, index) =>
  <li key={index}> /* Still not recommended but preferred over nanoid().
                      Only do this if items have no stable IDs. */
    {text}
  </li>
)

In case you just need random IDs to link elements like labels and input fields together, useId is recommended. That hook was added in React 18.

React Native

React Native does not have built-in random generator. The following polyfill works for plain React Native and Expo starting with 39.x.

  1. Check react-native-get-random-values docs and install it.
  2. Import it before Nano ID.
import 'react-native-get-random-values'
import { nanoid } from 'nanoid'

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:

db.put({
  _id: 'id' + nanoid(),})

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.

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.

$ npx nanoid
npx: installed 1 in 0.63s
LZfXLFzPPR4NNrgjlWDxn

Size of generated ID can be specified with --size (or -s) option:

$ npx nanoid --size 10
L3til0JS4z

Custom alphabet can be specified with --alphabet (or -a) option (note that in this case --size is required):

$ npx nanoid --alphabet abc --size 15
bccbcabaabaccab

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.

For other environments, CLI is available to generate IDs from a command line.

Tools

nanoid's People

Contributors

ai avatar aidarkhanov avatar antiflasher avatar artalar avatar brooooooklyn avatar cyberap avatar davidklebanoff avatar dependabot[bot] avatar eugeno avatar ganapativs avatar gwer avatar hojberg avatar jamoca avatar kateile avatar maxgraey avatar nik-sta avatar pd4d10 avatar polemius avatar sbrichardson avatar spa5k avatar stefansundin avatar steveedson avatar subzey avatar swernerx avatar tglide avatar theseally avatar thomassth avatar tigt avatar vitalybaev avatar zelark avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nanoid's Issues

nanoid in Go

Disclaimer

I am aware of #20.
The fact is that I wasn't aware of it 24 hours ago, when I started playing around with this port of mine.

Description

I have documented well my code, added references to the original repo (you can see many Github links inside nanoid.go and ported the test suite at test/index.test.js).

The main difference with matoous/go-nanoid is that I've strictly followed the original API. Thus, I feel it would be nice to add a link to my repo just below @matoous'

Thus the last part of README.md would become:

Other Programming Languages

@ai, what do you thunk about it?

Why not 21 symbols instead of 22?

Reading through the README, it sounds you arrived at the number of symbols so that Nano Id has a greater than or equal number of unique combinations when compared to UUID v4. Right?

According to wiki, UUID v4 has 122 bits that contribute to randomness.

Default Nano ID has a (26+26+10+2 = 64) symbol alphabet (6 bits). So with 6 bits per symbol, and 22 symbols, we arrive at (6*22 = 132) total bits.

So we could totally drop the number of symbols down to 21 (126 bits) and still have more unique combinations than UUID v4.

Saves everyone 1 whole symbol! Unless of course I'm missing something, which is very much possible.

CLJS: Strings dont have a length attribute...

Ran in to this error when I try to use a custom generator.

(def hex-id-generator (generate "0123456789abcdef"))

Exception

Uncaught TypeError: id.length is not a function
    at nano_id.custom.generate.cljs$core$IFn$_invoke$arity$2 (custom.cljc?rel=1531759015549:22)
    at my_tool$events$generate_system_key (events.cljs?rel=1531759024127:14)
    at events.cljs?rel=1531759024127:96
    at std_interceptors.cljc?rel=1531759023484:115
    at re_frame$std_interceptors$db_handler__GT_interceptor_$_db_handler_before (std_interceptors.cljc?rel=1531759023484:111)
    at re_frame$interceptor$invoke_interceptor_fn (interceptor.cljc?rel=1531759014576:68)
    at re_frame$interceptor$invoke_interceptors (interceptor.cljc?rel=1531759014576:106)
    at re_frame$interceptor$execute (interceptor.cljc?rel=1531759014576:199)
    at re_frame$events$handle (events.cljc?rel=1531759022762:65)
    at re_frame.router.EventQueue.re_frame$router$IEventQueue$_process_1st_event_in_queue$arity$1 (router.cljc?rel=1531759022973:178)
    at re_frame$router$_process_1st_event_in_queue (router.cljc?rel=1531759022973:84)
    at re_frame.router.EventQueue.re_frame$router$IEventQueue$_run_queue$arity$1 (router.cljc?rel=1531759022973:197)
    at re_frame$router$_run_queue (router.cljc?rel=1531759022973:86)
    at router.cljc?rel=1531759022973:145
    at re_frame.router.EventQueue.re_frame$router$IEventQueue$_fsm_trigger$arity$3 (router.cljc?rel=1531759022973:168)
    at re_frame$router$_fsm_trigger (router.cljc?rel=1531759022973:80)
    at router.cljc?rel=1531759022973:186

Environment;

[org.clojure/clojurescript "1.10.238"]
                 [reagent "0.7.0"]
                 [re-frame "0.10.5"]
                 [nano-id "0.9.2"]
                 [com.andrewmcveigh/cljs-time "0.5.2"]

Define forbidden characters for first, last position and leading character

Many people like me use this library as unique URL identifier and it works really good.

One thing should be better to generate friendly URLs. Restrict first and last characters like underscore and tilde ( _ ~ ) from default character set.
It is better human readable when ID is something like this: 0BM_z7D than this 0BMOz7_ or ~BMOz7D.

Same case why we should restrict special characters is when they leading next to each other.
Currently we can get some of these combinations: 0B__z7D, 0B~_z7D which also doesn't look so good.

Is it safe to prepend a prefix to a generated ID?

Kind of simple question, but better safe then sorry :)
Example:

const generate = require('nanoid/generate');
const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const prefix = 'myCustomPrefix';
const identifier =  prefix + generate(alphabet, 12);

Is that anything to worry about?
Thanks for help in advance.

[Question] How do you get 310 ?

Hi, ai. I was reading your code and found var step = Math.ceil(310 / alphabet.length * size) in format.js.

Would you mind telling me how you choose 310? instead of 256?

Thanks a lot!

[Question] Comparison with UUID

Do you have a comparison with UUID on likelihood of collisions? For example, I've read on Wikipedia that for UUIDs that is "50% probability of at least one collision when generating 1 billion UUIDs per second for about 85 years". Does nanoid have such claims?

Ruby implementation

Hello,
i like this random generator.

In our-project we need some cluster-safe generator uniq, short and human friendly. We have tried Hashids, but it doesn't fulfil our expectations.

Our backend is written in Ruby language so i reimplement your original algorithm in ruby:
https://github.com/radeno/nanoid.rb

Node 9 in Travis Ci config

Not sure if we should just test 6, 8 and 10 (like in most projects) or is it intended to also test Node.js 9?

Can I help? Is it possible to generate unguessable nanoid's on ReactNative?

Hey,

Thanks for building this - very cool and I appreciate all the hard work you do on it! :-)

I notice that the README says nanoid doesn't generate unpredictable ids on RN due to the lack of a secure RNG. However, would it be possible to use something like https://www.npmjs.com/package/react-native-securerandom for example?

I was thinking to avoid a dependency on this third-party RN package, maybe we could use dependency injection to inject a secure RNG, user's choice, and give instructions for simultaneously adding this react-native-securerandom. So current users would not be impacted since current defaults would work. But new users could pass in a reference to some function that uses react-native-securerandom to supply the secure random bytes (via a promise).

I'd be happy to work on a PR for this if there's interest, but could you give me a few pointers where to get started in nanoid, like where to do the dependency injection and roughly how and I could give it a shot?

Thanks1

Add alternative Python implementation in README

Ported many tests and code follows new Nano ID 2.0 https://github.com/aidarkhanov/py-nanoid

Though, I have discussed with Paul Yuan, maintainer of https://github.com/puyuan/py-nanoid, an update of his project to the new version and we have agreed upon a merge.

Nevertheless, my project has one more case - port of Nano ID dictionary to Python.

Why adding another implementation to the list?
In my opinion, having another point of view and providing another option to a user is great opportunity to increase popularity of Nano ID.

Uniformity tests required

Some test is required to validate e.g. that produced strings are keeping probability of (at least) all chars same with known probability (e.g. 5%).

v1.2.4 breaks compatibility with Node.js 6

The crypto.randomFillSync was added in the Node.js v7.10.0. Node.js 6.x is in the Long Term Support status until April 2019. Requirement of crypto.randomFillSync is a breaking change for Node.js 6.x users.

Could you please republish v1.2.3 as v1.2.5, and v1.2.4 as v2.0.0 to be more SemVer-friendly, or at least specify the correct engines field in the package.json?

Can this be used to convert existing bytes?

If I already have an existing 16 bytes of a uuid, can I use nanoid to generate a shorter id from that (providing a given alphabet) and also ensuring an even distribution of generated ids? I suppose the generated id length would vary in that case so I suppose the even distribution wouldn't work?

Changelog for v2?

Hey there,

What's the reason you jumped from v1.3.4 to v2? What are the breaking changes and how can I update my code? It would be great if you could make this obvious and maybe include it in the readme file.

Thanks

Create collision calculator

UUID collision probability is too low for many users. Many of users want to have smaller ID and smaller alphabet. It will be good to give them a collision: alphabet + ID length + IDs/hour → years of work before 1% collision

React Native support

I found a problem while running on React Native.
image uploaded from ios
Are there any plans to support React Native?

Enable Support for Patterns

Is it possible to generate id based on a given pattern
e.g.
generate('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', 5); //returns 5LSHO
could be extended to
generate('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ', 5, 'XXX-XX'); //could return 5LS-HO

Uniformity questions/discussion

The security section proclaims random % alphabet to be insecure, and it understandably is, when the range of random isn't divisible by the length of alphabet and parts of the random space get "folded" into the smaller space. (I'm sure there's a mathematical term for this...) Anyway, it would be nice if the readme explained why the above algorithm is bad.

So I started wondering about the usual Math.random() * alphabet.length approach and tested it a bit: https://gist.github.com/akx/7afb144ed2b4d32886a29bfd45e7986f

With 100,000 characters generated, the distribution seems reasonably uniform:

image

(The "dip" at the lower values disappears on subsequent runs, so it's nothing to worry about.)

However, using const cryptoRand = () => crypto.randomBytes(1)[0] / 255.; as the rand function, the distribution is significantly non-uniform, which is kind of strange. (Can someone explain what's happening there?)

image

  • The same profile remained over multiple trials.
  • The same profile occurs on both OSX and Moby Linux, as run by Docker-on-Mac.
  • Also, to rule out any weirdness that might be caused by requesting only one byte at a time, I tested with an approach that fills in a larger buffer of randomBytes.

(ps. What's the magic 1.6 in

var step = Math.ceil(1.6 * mask * size / alphabet.length)
? :D )

[Question] What is the collision probability with a reduced alphabet size and/or reduced ID length?

@ai
Currently nanoid by default uses A-Za-z0-9_~ for its alphabet. Now if we reduce the alphabet to human readable characters, say, A-Z, 0-9, excluding the commonly confused 01OI, what would be the impact on collision probability in nanoid?

And, if we reduce the ID length from 22 symbols to say 10 symbols, how would the uniqueness be effected in a single processor and/or multi-processor scenario?

Add Chinese docs

@wenliangdai @gucong3000 hi, thanks for the help in translating PostCSS docs.

This project got 1M/month downloads. Maybe you want to translate it too? The docs are not so big. And it will be a good reason to mention your in tweets. =^_^=

Id length is actually max-length

Hi, your concern seems to be only with key collisions, which is fine. But I also want (visual) uniformity. I would suggest to make the length the exact same size as requested.

Thanks

Option to change defaults?

I know there is a generate method, to change the alphabet and length of the id that will be generated.

The case is; I need to migrate my id generation away from Meteor/Random, while I also don't want my id's to start look different.

I can achieve this with:

const generate = require('nanoid/generate');
const alphabet = '23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz';
const length = 17;

generate(alphabet, length); // D8taKDubtMzi58jZn

But, that means that I need to specify this alphabet and length on every place where I need an ID.

It would be nice if there was a method to change the defaults so that the next require('nanoid')() uses custom settings.

// main.js
const nano = require('nanoid');
nano.config({
  alphabet: '23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz',
  length: 17,
});

// some-other-file.js
const nano = require('nanoid');
nano(); // Kg6gwCgG44zEK8u6g

Nanoid in python

@ai I have ported nanoid in python while experimenting with it in my own project.

You can check my work here:

https://github.com/puyuan/py-nanoid

TODOs:
I haven't included your simpler 64 alphabet algorithm yet (will do so when I have time), currently its based on the general algorithm.

If you find it ok, perhaps you can help me link the python version.

nanoid in PHP

Dear Andrey:

I am a PHPer,you can call me Chen.I star your nanoid lib and I checked the source code,then I make a copy from your Javascript version in PHP.
But I have some issue in index.js,I do not understand why that is different algorithm between formart.js for generate id or I just misunderstood?

PS: Here is my PHP version nano-id, if you have time and interest,check it: https://github.com/hidehalo/nanoid-php
Thank you!!

Nano ID Collision Calculator freezes sometimes

The IDs per hour allowed by the calculator should be 1or more. If I intend to type 10 and start with "1", the entire page freezes.

It would be better if the page just says, "The speed should be 1 or more" , like it says when the input field is blank.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.