Instantly share code, notes, and snippets.

Embed
What would you like to do?
generate random UUIDs

UUID

Returns a random v4 UUID of the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, where each x is replaced with a random hexadecimal digit from 0 to f, and y is replaced with a random hexadecimal digit from 8 to b.

There's also @LeverOne's approach using iteration, which is one byte shorter.

function b(
a // placeholder
){
return a // if the placeholder was passed, return
? ( // a random number from 0 to 15
a ^ // unless b is 8,
Math.random() // in which case
* 16 // a random number from
>> a/4 // 8 to 11
).toString(16) // in hexadecimal
: ( // or otherwise a concatenated string:
[1e7] + // 10000000 +
-1e3 + // -1000 +
-4e3 + // -4000 +
-8e3 + // -80000000 +
-1e11 // -100000000000,
).replace( // replacing
/[018]/g, // zeroes, ones, and eights with
b // random hex digits
)
}
function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 Jed Schmidt <http://jed.is>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "UUID",
"description": "Generates random UUIDs",
"keywords": [
"UUID",
"ID",
"random"
]
}
@subzey

This comment has been minimized.

subzey commented Aug 12, 2011

We can use coercion and exponential notation to get template string and save 7 bytes:
function(){return(""+1e7+-1e3+-4e3+-8e3+-1e11).replace(/1|0/g,function(){return(0|Math.random()*16).toString(16)})}

@jed

This comment has been minimized.

Owner

jed commented Aug 13, 2011

subzey, you are a genius. fixing and annotating now.

@jed

This comment has been minimized.

Owner

jed commented Aug 13, 2011

you also inspired me to cut 10 more bytes out:

function b(a){return a?(0|Math.random()*16).toString(16):(""+1e7+-1e3+-4e3+-8e3+-1e11).replace(/1|0/g,b)}
@jed

This comment has been minimized.

Owner

jed commented Aug 13, 2011

(0|Math.random()*16).toString(16)

can also be trimmed 4 bytes to

Math.random().toString(16)[2]

if you don't care about IE... thoughts?

@subzey

This comment has been minimized.

subzey commented Aug 13, 2011

@jed, Math.random() may return 0, so Math.random().toString(16)[2] may return undefined.

Also, isn't setting name of function affects the outer scope?

@jed

This comment has been minimized.

Owner

jed commented Aug 13, 2011

well, with the chance of Math.random returning a zero 1 in 2<<61, seems like the definition of an edge case. more likely that IE barfs on it.

also, we're allowing named functions because we assume that they'll be assigned externally.

@subzey

This comment has been minimized.

subzey commented Aug 13, 2011

@jed, thanks for your clarification about function names, I didn't know that

@jed

This comment has been minimized.

Owner

jed commented Aug 15, 2011

@subzey, i hope you use this knowledge to bring us some awesome new stuff.

@LeverOne

This comment has been minimized.

LeverOne commented Oct 6, 2011

""+1e7+-1e3+-4e3+-8e3+-1e11 --> [1e7]+-1e3+-4e3+-8e3+-1e11
it's а flaw of many of you.

@subzey

This comment has been minimized.

subzey commented Oct 7, 2011

@LeverOne, perfect! Thanks

@jed

This comment has been minimized.

Owner

jed commented Oct 7, 2011

wow, that's crazy. good work @LeverOne.

@fgnass

This comment has been minimized.

fgnass commented Oct 7, 2011

What about replacing /1|0/ with /\d/?

@jed

This comment has been minimized.

Owner

jed commented Oct 7, 2011

the 4 is hardcoded according to the spec, and the 8 is a bit of a hack... technically it should be anything from 8 to b. so replacing those would make it less compliant.

@fgnass

This comment has been minimized.

fgnass commented Oct 7, 2011

Ah I see, I missed that.

@jed

This comment has been minimized.

Owner

jed commented Oct 7, 2011

i wonder if we finally have enough bytes to make it compliant, such that the 8 can be 8, 9, a, or b...

@subzey

This comment has been minimized.

subzey commented Oct 7, 2011

It is enough already :)

function c(a,b){return a?(~~b+0|Math.random()*16>>b/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/1|0|(8)/g,c)}
@subzey

This comment has been minimized.

subzey commented Oct 7, 2011

Or this, shorter:

function c(a,b){return a?(b|Math.random()*16>>b/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/1|0|(8)/g,c)}
@jed

This comment has been minimized.

Owner

jed commented Oct 7, 2011

thanks again, @subzey. updated.

@broofa

This comment has been minimized.

broofa commented Oct 7, 2011

Line 20 of annotated.js should be 'c', not 'b'.

BTW, you're all insane. I love it! :)

@jed

This comment has been minimized.

Owner

jed commented Oct 7, 2011

good catch! for those not in the know, @broofa is a celebrity in the world of UUIDs: https://github.com/broofa/node-uuid

@tsaniel

This comment has been minimized.

tsaniel commented Oct 9, 2011

Maybe save 4 bytes...?


@jed

This comment has been minimized.

Owner

jed commented Oct 9, 2011

what the... how on earth does this work?

@tsaniel

This comment has been minimized.

tsaniel commented Oct 9, 2011

There are three possible values 0,1,8 for a.

For case 0: 0^Math.random()*16>>0/4, >>0/4 is actually >>0, just works as Math.floor.
The 0^ here does nothing.

For case 1: 1^Math.random()*16>>1/4, >>1/4 is still >>0.
Although 1^ here toggles the least significant bit, we can still use it to generate random numbers 0-15.

For case 8: 8^Math.random()*16>>8/4, >>8/4 turns out >>2.
The maximum number of Math.random()*16 in binary form is 1111, that means the range is 0000-1111.
By right shifting 2 bits, the maximum number of Math.random()*16>>2 is 0011, and the range, 0000-0011. What it does here is to generate random numbers 0-3.
Finally, because the most significant bit is always 0, 8^ is actually 8|, it is to ensure the range starts from 8. And now we get 8 + {0, 1, 2, 3}.

@jed

This comment has been minimized.

Owner

jed commented Oct 9, 2011

incredible work, @tsaniel!

@jed

This comment has been minimized.

Owner

jed commented Oct 9, 2011

it's amazing how this gist has evolved, from

function(){return"00000000-0000-4000-8000-000000000000".replace(/0/g,function(){return(0|Math.random()*16).toString(16)})}

to

function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}

while hitting all the greatest hits: recursion, coercion of a number into a string through an array (!), operator repurposing...

@tsaniel

This comment has been minimized.

tsaniel commented Oct 9, 2011

I love those tricks, especially the string coercion with array, though i love bitwise tricks.
By the way, i am still thinking if we can shorten /[018]/...

@atk

This comment has been minimized.

atk commented Oct 9, 2011

@tsaniel - no way, the other way round would be /[^4-]/, which is just as long.

@tsaniel

This comment has been minimized.

tsaniel commented Oct 9, 2011

@atk: That's true. I mean if we can do something to use /\d/ instead.

@atk

This comment has been minimized.

atk commented Oct 9, 2011

...which would require that the 4 will be left alone and enlarge the equation probably more than the 3 letters we saved.

@tsaniel

This comment has been minimized.

tsaniel commented Oct 9, 2011

Maybe that's the end.

@atk

This comment has been minimized.

atk commented Oct 9, 2011

I fear it is.

@subzey

This comment has been minimized.

subzey commented Oct 11, 2011

Once again, excellent work, @tsaniel!

Sorry for my late comment, my mobile browser doesn't work well with github

@LeverOne

This comment has been minimized.

LeverOne commented Oct 24, 2011

Recursion & coercion vs. loop & math: https://gist.github.com/1308368

@jed

This comment has been minimized.

Owner

jed commented Oct 24, 2011

just when you thought it couldn't get any shorter, @LeverOne sheds a byte. good job!

@tsaniel

This comment has been minimized.

tsaniel commented Oct 24, 2011

@LeverOne is my hero.

@kalupa

This comment has been minimized.

kalupa commented Jun 20, 2013

damnit jed, i keep finding you everywhere. thanks for this!

@jussi-kalliokoski

This comment has been minimized.

jussi-kalliokoski commented Jun 27, 2013

In Firefox you could use the single statement function body to shorten it a few bits still:

function b(a)a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)
@jussi-kalliokoski

This comment has been minimized.

jussi-kalliokoski commented Jun 27, 2013

Shorter yet (cheats, ES6, and works only in Firefox!!!), and less leaky:

function()([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,a=>(a^Math.random()*16>>a/4).toString(16))
@jussi-kalliokoski

This comment has been minimized.

jussi-kalliokoski commented Jun 27, 2013

Hah, since I already used ES6 and there are no variable assignments, might as well go all the way and avoid Firefox-only stuff:

()=>([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,a=>(a^Math.random()*16>>a/4).toString(16))
@jameswyse

This comment has been minimized.

jameswyse commented Jul 29, 2013

This is awesome!

Here's a benchmark vs node-uuid: http://jsperf.com/node-uuid-performance/11

@ronkorving

This comment has been minimized.

ronkorving commented Aug 22, 2013

I was so rooting for Crazy Gist to win that one :(

@thelinuxlich

This comment has been minimized.

thelinuxlich commented Oct 24, 2015

Is this relatively safe to generate UUIDs simultaneously between many clients?

@coolaj86

This comment has been minimized.

coolaj86 commented Nov 8, 2015

Make it secure at the cost of just a few bytes by replacing Math.random() * 16:

browser

crypto.getRandomValues(new Uint8Array(1))[0] % 16

function b(
  a                  // placeholder
){
  return a           // if the placeholder was passed, return
    ? (              // a random number from 0 to 15
      a ^            // unless b is 8,
      crypto.getRandomValues(new Uint8Array(1))[0]  // in which case
      % 16           // a random number from
      >> a/4         // 8 to 11
      ).toString(16) // in hexadecimal
    : (              // or otherwise a concatenated string:
      [1e7] +        // 10000000 +
      -1e3 +         // -1000 +
      -4e3 +         // -4000 +
      -8e3 +         // -80000000 +
      -1e11          // -100000000000,
      ).replace(     // replacing
        /[018]/g,    // zeroes, ones, and eights with
        b            // random hex digits
      )
}

node.js

crypto.randomBytes(1)[0] % 16

function b(
  a                  // placeholder
){
  return a           // if the placeholder was passed, return
    ? (              // a random number from 0 to 15
      a ^            // unless b is 8,
      crypto.randomBytes(1)[0]  // in which case
      % 16           // a random number from
      >> a/4         // 8 to 11
      ).toString(16) // in hexadecimal
    : (              // or otherwise a concatenated string:
      [1e7] +        // 10000000 +
      -1e3 +         // -1000 +
      -4e3 +         // -4000 +
      -8e3 +         // -80000000 +
      -1e11          // -100000000000,
      ).replace(     // replacing
        /[018]/g,    // zeroes, ones, and eights with
        b            // random hex digits
      )
}
@dalanmiller

This comment has been minimized.

dalanmiller commented Nov 10, 2015

@coolaj89 I don't have crypto.randomBytes in Chrome 46.0.2490.80 but there is crypto.getRandomValues

@aichholzer

This comment has been minimized.

aichholzer commented Sep 5, 2016

And even smaller now:

b = a=>a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b);
@Kiodaddy

This comment has been minimized.

Kiodaddy commented Jun 20, 2017

I am having issue in 3rd file and i am not able to correct it .

@GraniteConsultingReviews

This comment has been minimized.

GraniteConsultingReviews commented Aug 27, 2017

Great This works well thanks

@fergusean

This comment has been minimized.

fergusean commented Aug 30, 2017

in the annotated version:

-8e3 +         // -80000000 +

should be

-8e3 +         // -8000 +
@GraniteConsultingReviews

This comment has been minimized.

GraniteConsultingReviews commented Sep 7, 2017

I try this code but this is not generating random UUIDs

@Liath

This comment has been minimized.

Liath commented Oct 23, 2017

@coolaj89's you can golf that down a little:
([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b=>(b^crypto.rng(1)[0]%16>>b/4).toString(16))
crypto.rng is the same as crypto.randomBytes on a stock node.js build.

@Native-Coder

This comment has been minimized.

Native-Coder commented Nov 22, 2017

You guys are freaking insane...I love it...

@sowmitranalla

This comment has been minimized.

sowmitranalla commented Dec 5, 2017

this was a wonderful thread to read

@ghost

This comment has been minimized.

ghost commented Dec 23, 2017

@coolaj89 for the browser version you can shave off another char by replacing:

new Uint8Array(1)

with (not supported in all browsers, of course):

Uint8Array.of(0)
@Louies89

This comment has been minimized.

Louies89 commented Jan 4, 2018

@jussi-kalliokoski
For Nodejs, below change has to be done:
()=>([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,a=>((a^crypto.randomBytes(1)[0]*16>>a/4).toString(16))[0])

@seanlindo

This comment has been minimized.

seanlindo commented Mar 3, 2018

This is fantastic.

@Elephant-Vessel

This comment has been minimized.

Elephant-Vessel commented Mar 7, 2018

Awesome. Is there a readable non-golfed version of this code?

@miniak

This comment has been minimized.

miniak commented Mar 17, 2018

you can use this `${1e7}-${1e3}-${4e3}-${8e3}-${1e11}` to make it clear that it's a string

@mindplay-dk

This comment has been minimized.

mindplay-dk commented Apr 6, 2018

Awesome. Is there a readable non-golfed version of this code?

Here's a more readable (verbose, RFC-compliant) version using crypto API:

var hex = [];

for (var i = 0; i < 256; i++) {
    hex[i] = (i < 16 ? '0' : '') + (i).toString(16);
}

function makeUUID() {
    var r = crypto.getRandomValues(new Uint8Array(16));

    r[6] = r[6] & 0x0f | 0x40;
    r[8] = r[8] & 0x3f | 0x80;

    return (
        hex[r[0]] +
        hex[r[1]] +
        hex[r[2]] +
        hex[r[3]] +
        "-" +
        hex[r[4]] +
        hex[r[5]] +
        "-" +
        hex[r[6]] +
        hex[r[7]] +
        "-" +
        hex[r[8]] +
        hex[r[9]] +
        "-" +
        hex[r[10]] +
        hex[r[11]] +
        hex[r[12]] +
        hex[r[13]] +
        hex[r[14]] +
        hex[r[15]]
    );
}
@MikeFielden

This comment has been minimized.

MikeFielden commented May 7, 2018

I have nothing excellent to offer other than I have REALLY enjoyed reading this :)

@pb-nati

This comment has been minimized.

pb-nati commented May 17, 2018

This is amazing. Small piece of code to do something simple.

@PaulCordo

This comment has been minimized.

PaulCordo commented May 24, 2018

What's this [1e7] part for that Typescript refuse to compile saying "Operator '+' cannot be applied to types 'number[]' and '-1000'." ?

@AJamesPhillips

This comment has been minimized.

AJamesPhillips commented May 29, 2018

@PaulCordo it's because these insane(ly amazing) authors want to convert 1e7 into a string and because [1e7]+-1e3 is 1 byte shorter than ""+1e7+-1e3! :) A bit more info and an example: https://stackoverflow.com/q/9300941/539490

@eric1iu

This comment has been minimized.

eric1iu commented Jun 15, 2018

wow! amazing!

@edo9k

This comment has been minimized.

edo9k commented Jul 6, 2018

NICE!

@dehghani-mehdi

This comment has been minimized.

dehghani-mehdi commented Jul 21, 2018

After reading comments, I figure out I don't nothing about JS, really great job, thank you !!

@faazshift

This comment has been minimized.

faazshift commented Jul 28, 2018

I came here from the link in the README of kelektiv/node-uuid. I've tested v4 of that implementation, including forcing it to use the non cryptographically safe Math.random() for random number generation, and found it to be pretty reliably unique over many millions of iterations. However, this mini UUID function pretty reliably runs into collisions after 20-30 million iterations. Not entirely sure what the design flaw is, but for UUIDs that need to be guaranteed unique, it's probably best not to use this function in its present form in mission-critical code. Other than that, nice work on creating such a compact ID generator.

@BerlinChan

This comment has been minimized.

BerlinChan commented Sep 19, 2018

I like this LICENSE! That is awosome and so easy to understand!

@handicraftsman

This comment has been minimized.

handicraftsman commented Sep 25, 2018

Lol

@LDubya

This comment has been minimized.

LDubya commented Oct 29, 2018

Such collaboration. This is what the internet was made for.

@smurp

This comment has been minimized.

smurp commented Nov 2, 2018

Who's reading this at 2018-11-02T09:07:56Z ?

@rmpel

This comment has been minimized.

rmpel commented Nov 9, 2018

I. F*KING. LOVE. THIS.

I would have NEVER EVER thought of doing this like this!

Amazing work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment