2830

I want a 5 character string composed of characters picked randomly from the set [a-zA-Z0-9].

What's the best way to do this with JavaScript?

5

94 Answers 94

3701

I think this will work for you:

function makeid(length) {
    let result = '';
    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    const charactersLength = characters.length;
    let counter = 0;
    while (counter < length) {
      result += characters.charAt(Math.floor(Math.random() * charactersLength));
      counter += 1;
    }
    return result;
}

console.log(makeid(5));

21
3182

//Can change 7 to 2 for longer results.
let r = (Math.random() + 1).toString(36).substring(7);
console.log("random", r);

Note: The above algorithm has the following weaknesses:

  • It will generate anywhere between 0 and 6 characters due to the fact that trailing zeros get removed when stringifying floating points.
  • It depends deeply on the algorithm used to stringify floating point numbers, which is horrifically complex. (See the paper "How to Print Floating-Point Numbers Accurately".)
  • Math.random() may produce predictable ("random-looking" but not really random) output depending on the implementation. The resulting string is not suitable when you need to guarantee uniqueness or unpredictability.
  • Even if it produced 6 uniformly random, unpredictable characters, you can expect to see a duplicate after generating only about 50,000 strings, due to the birthday paradox. (sqrt(36^6) = 46656)
23
  • 332
    Math.random().toString(36).substr(2, 5), because .substring(7) causes it to be longer than 5 characters. Full points, still!
    – dragon
    May 7, 2012 at 8:13
  • 86
    @Scoop The toString method of a number type in javascript takes an optional parameter to convert the number into a given base. If you pass two, for example, you'll see your number represented in binary. Similar to hex (base 16), base 36 uses letters to represent digits beyond 9. By converting a random number to base 36, you'll wind up with a bunch of seemingly random letters and numbers. Jan 3, 2013 at 20:45
  • 85
    Looks beautiful but in few cases this generates empty string! If random returns 0, 0.5, 0.25, 0.125... will result in empty or short string.
    – gertas
    Mar 15, 2013 at 19:55
  • 82
    @gertas This can be avoided by (Math.random() + 1).toString(36).substring(7); Aug 11, 2013 at 17:17
  • 35
    @hacklikecrack, the duplicates occur because substring(7) takes the digits from the least significant part of the base-36 string. toString(36) appears to convert the random number to a 16 digit base-36 string, but the precision required for this would be 36^16 = 7.958e24 possible numbers, where the precision of Math.random() is only 4.5e15. Taking the digits from most significant end with .slice(2,5) solves this: 5 digit example
    – Luke
    Dec 4, 2014 at 0:48
938

Math.random is bad for this kind of thing

server side

Use node crypto module -

var crypto = require("crypto");
var id = crypto.randomBytes(20).toString('hex');

// "bb5dc8842ca31d4603d6aa11448d1654"

The resulting string will be twice as long as the random bytes you generate; each byte encoded to hex is 2 characters. 20 bytes will be 40 characters of hex.


client side

Use the browser's crypto module -

const id = window.crypto.randomUUID()
console.log(id)
// bd4d099b-3d39-4aad-a59c-c45dfac8eaf0

Or crypto.getRandomValues -

The crypto.getRandomValues() method lets you get cryptographically strong random values. The array given as the parameter is filled with random numbers (random in its cryptographic meaning).

// dec2hex :: Integer -> String
// i.e. 0-255 -> '00'-'ff'
function dec2hex (dec) {
  return dec.toString(16).padStart(2, "0")
}

// generateId :: Integer -> String
function generateId (len) {
  var arr = new Uint8Array((len || 40) / 2)
  window.crypto.getRandomValues(arr)
  return Array.from(arr, dec2hex).join('')
}

console.log(generateId())
// "82defcf324571e70b0521d79cce2bf3fffccd69"

console.log(generateId(20))
// "c1a050a4cd1556948d41"

A step-by-step console example -

> var arr = new Uint8Array(4) # make array of 4 bytes (values 0-255)
> arr
Uint8Array(4) [ 0, 0, 0, 0 ]

> window.crypto
Crypto { subtle: SubtleCrypto }

> window.crypto.getRandomValues()
TypeError: Crypto.getRandomValues requires at least 1 argument, but only 0 were passed

> window.crypto.getRandomValues(arr)
Uint8Array(4) [ 235, 229, 94, 228 ]

For IE11 support you can use -

(window.crypto || window.msCrypto).getRandomValues(arr)

For browser coverage see https://caniuse.com/#feat=getrandomvalues


client side (old browsers)

If you must support old browsers, consider something like uuid -

const uuid = require("uuid");
const id = uuid.v4();

// "110ec58a-a0f2-4ac4-8393-c866d813b8d1"
22
  • 7
    Exactly. While a UUID is fine for assigning an ID to a thing, using it as a string of random characters isn't a great idea for this (and probably other) reasons. Aug 4, 2015 at 17:42
  • 3
    No need for .map() in Option 3. Array.from(arr, dec2hex).join('') === Array.from(arr).map(dec2hex).join(''). Thanks for introducing me to these features :-)
    – Fred Gandt
    May 11, 2017 at 19:28
  • 7
    You should mention in the answer that option 2 also needs node.js to work, it's not pure javascript.
    – Esko
    Aug 21, 2018 at 11:47
  • 12
    While being more cryptographically secure, this doesn't actually satisfy the requirements of the question because it only outputs 0-9 and a-f (Hexadecimal), and not 0-9, a-z, A-Z.
    – qJake
    Oct 17, 2018 at 19:46
  • 1
    @AneesAhmed777 the dec2hex was provided an example encoder. It's up to you to represent the bytes however you choose. I updated the post with your suggestion.
    – Mulan
    Dec 1, 2020 at 17:29
328

Short, easy and reliable

Returns exactly 5 random characters, as opposed to some of the top rated answers found here.

Math.random().toString(36).slice(2, 7);
18
  • 25
    What if Math.random().toString(36) returns a number with less than 5 characters? Jan 17, 2017 at 11:42
  • 8
    Well, that's an interesting indictment from @Aperçu, I am not saying that I invented the solution but I've been using it in my projects for years now. And it has nothing to do with the comment you mentioned. And I am quite sure that in SO what matters is the most useful information in the right place and even if it already exists in some other place, too. Luckily, it seems like at least 51 guys have found this answer useful, you're welcome! Mar 5, 2017 at 11:10
  • 6
    @rinogo Math.random() can return 0 but not 1 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    – mikep
    Aug 4, 2017 at 9:54
  • 11
    I ran this code 1,000,000,000 times and still didn't get an empty string: jsfiddle.net/mtp5730r I would say you're pretty safe from getting an empty string.
    – MacroMan
    Jul 19, 2018 at 13:39
  • 26
    An event being statistically unlikely does not make it safe. If anyone is using this for any security related activity they are gambling on the improbability of Math.random not returning 0. Hope you never have to debug this event
    – Purefan
    Mar 14, 2019 at 17:26
191

Here's an improvement on doubletap's excellent answer. The original has two drawbacks which are addressed here:

First, as others have mentioned, it has a small probability of producing short strings or even an empty string (if the random number is 0), which may break your application. Here is a solution:

(Math.random().toString(36)+'00000000000000000').slice(2, N+2)

Second, both the original and the solution above limit the string size N to 16 characters. The following will return a string of size N for any N (but note that using N > 16 will not increase the randomness or decrease the probability of collisions):

Array(N+1).join((Math.random().toString(36)+'00000000000000000').slice(2, 18)).slice(0, N)

Explanation:

  1. Pick a random number in the range [0,1), i.e. between 0 (inclusive) and 1 (exclusive).
  2. Convert the number to a base-36 string, i.e. using characters 0-9 and a-z.
  3. Pad with zeros (solves the first issue).
  4. Slice off the leading '0.' prefix and extra padding zeros.
  5. Repeat the string enough times to have at least N characters in it (by Joining empty strings with the shorter random string used as the delimiter).
  6. Slice exactly N characters from the string.

Further thoughts:

  • This solution does not use uppercase letters, but in almost all cases (no pun intended) it does not matter.
  • The maximum string length at N = 16 in the original answer is measured in Chrome. In Firefox it's N = 11. But as explained, the second solution is about supporting any requested string length, not about adding randomness, so it doesn't make much of a difference.
  • All returned strings have an equal probability of being returned, at least as far as the results returned by Math.random() are evenly distributed (this is not cryptographic-strength randomness, in any case).
  • Not all possible strings of size N may be returned. In the second solution this is obvious (since the smaller string is simply being duplicated), but also in the original answer this is true since in the conversion to base-36 the last few bits may not be part of the original random bits. Specifically, if you look at the result of Math.random().toString(36), you'll notice the last character is not evenly distributed. Again, in almost all cases it does not matter, but we slice the final string from the beginning rather than the end of the random string so that short strings (e.g. N=1) aren't affected.

Update:

Here are a couple other functional-style one-liners I came up with. They differ from the solution above in that:

  • They use an explicit arbitrary alphabet (more generic, and suitable to the original question which asked for both uppercase and lowercase letters).
  • All strings of length N have an equal probability of being returned (i.e. strings contain no repetitions).
  • They are based on a map function, rather than the toString(36) trick, which makes them more straightforward and easy to understand.

So, say your alphabet of choice is

var s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

Then these two are equivalent to each other, so you can pick whichever is more intuitive to you:

Array(N).join().split(',').map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('');

and

Array.apply(null, Array(N)).map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('');

Edit:

I seems like qubyte and Martijn de Milliano came up with solutions similar to the latter (kudos!), which I somehow missed. Since they don't look as short at a glance, I'll leave it here anyway in case someone really wants a one-liner :-)

Also, replaced 'new Array' with 'Array' in all solutions to shave off a few more bytes.

8
  • Why not just add 1? (Math.random()+1).toString(36).substring(7);
    – Mike Doe
    Jan 8, 2015 at 10:00
  • Because adding 1 doesn't solve either of the two issues discussed here. For example, (1).toString(36).substring(7) produces an empty string.
    – amichair
    Jan 19, 2015 at 11:36
  • Using Math.random().toString(36).substring(2,7) gives an expected result which is more like the .substring(2, n+2)
    – Joseph Rex
    Nov 13, 2015 at 13:04
  • Array.apply(null, {length: 5}).map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('') Nov 13, 2015 at 14:54
  • This is great, but when executed in Firefox with N=16, the last ~6 digits end up being zero... (But it does satisfy the OP's desire for 5 random chars though.) Jun 10, 2016 at 23:15
160

The most compact solution, because slice is shorter than substring. Subtracting from the end of the string allows to avoid floating point symbol generated by the random function:

Math.random().toString(36).slice(-5);

or even

(+new Date).toString(36).slice(-5);

Update: Added one more approach using btoa method:

btoa(Math.random()).slice(0, 5);
btoa(+new Date).slice(-7, -2);
btoa(+new Date).substr(-7, 5);

// Using Math.random and Base 36:
console.log(Math.random().toString(36).slice(-5));

// Using new Date and Base 36:
console.log((+new Date).toString(36).slice(-5));

// Using Math.random and Base 64 (btoa):
console.log(btoa(Math.random()).slice(0, 5));

// Using new Date and Base 64 (btoa):
console.log(btoa(+new Date).slice(-7, -2));
console.log(btoa(+new Date).substr(-7, 5));

7
  • Math.random().toString(36).slice(-5); - What if Math.random() returns 0.0?
    – x-ray
    Jul 12, 2019 at 16:00
  • @x-ray, you will get "0" ;) Jul 13, 2019 at 4:13
  • 3
    Exactly. ;) And if Math.random() returns 0.5 the result is "0.i". Not sure if there are other edge cases. Just wanted to point out that this is not a correct answer to the question (5 characters from [a-zA-Z0-9]).
    – x-ray
    Jul 13, 2019 at 12:27
  • 2
    @x-ray, I'm not going to say that this is the right answer, I'm just saying that this is a compact version of the @doubletap answer above. I personally use (+new Date + Math.random()) to prevent this case. Anyway, thanks for the note. Jul 13, 2019 at 16:39
  • 1
    Why not using bota at all? I commented on other answers but using this test case you can see you going to use only 14 chars out of 64 that base64 has to offer: [...new Set([...Array(100000)].map(()=>btoa(Math.random()).substr(0, 5)).join(""))].sort()
    – Or Duan
    Nov 14, 2020 at 7:34
136

A newer version with es6 spread operator:

[...Array(30)].map(() => Math.random().toString(36)[2]).join('')

  • The 30 is an arbitrary number, you can pick any token length you want
  • The 36 is the maximum radix number you can pass to numeric.toString(), which means all numbers and a-z lowercase letters
  • The 2 is used to pick the 3rd index from the random string which looks like this: "0.mfbiohx64i", we could take any index after 0.
6
  • Could you explain? Especially why you pass 36 to toString() and why you choose the 3rd element?
    – vuza
    Dec 5, 2017 at 10:55
  • nice, but this solution doesn't include [A-Z] characters as question requested, only [a-z0-9] Mar 3, 2020 at 13:02
  • @NahuelGreco you can do [...Array(30)].map(() => Math.random().toString(36)[2]).join('').toUpperCase() Jul 20, 2020 at 0:56
  • @tam.teixeira I think no, original question asked for mixed caps, each char must be chosen at random from the [a-zA-Z0-9] set. This answer doesn't satisfies that. Jul 20, 2020 at 15:13
  • 2
    I would also add a || '0' so that it falls back to 0 instead of undefined if Math.random() returns 0 (it never returns 1)
    – Juan Campa
    Aug 7, 2022 at 16:29
119

Something like this should work

function randomString(len, charSet) {
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    var randomString = '';
    for (var i = 0; i < len; i++) {
        var randomPoz = Math.floor(Math.random() * charSet.length);
        randomString += charSet.substring(randomPoz,randomPoz+1);
    }
    return randomString;
}

Call with default charset [a-zA-Z0-9] or send in your own:

var randomValue = randomString(5);

var randomValue = randomString(5, 'PICKCHARSFROMTHISSET');
5
  • A variant of example here can be found here: mediacollege.com/internet/javascript/number/random.html
    – David
    Aug 31, 2012 at 18:17
  • 2
    might as well just decrement len directly in a while loop
    – drzaus
    Mar 6, 2013 at 14:59
  • Thanks, I just posted below a coffeescript variation of this example: stackoverflow.com/a/26682781/262379
    – Dinis Cruz
    Oct 31, 2014 at 20:20
  • If these are going to be used publically, then you should probably remove the vowels. A little less entropy, but a lot safer as you can't generate any words that may offend people. That is why I like this, since I can send in my own character string. Good job. Apr 18, 2017 at 18:22
  • note that on a Node server, it's this simple: crypto.randomBytes(3).toString('hex') (3 bytes gives 6 chars, for example)
    – Fattie
    May 5, 2022 at 18:00
78

function randomstring(L) {
  var s = '';
  var randomchar = function() {
    var n = Math.floor(Math.random() * 62);
    if (n < 10) return n; //1-10
    if (n < 36) return String.fromCharCode(n + 55); //A-Z
    return String.fromCharCode(n + 61); //a-z
  }
  while (s.length < L) s += randomchar();
  return s;
}
console.log(randomstring(5));

4
  • I like this the best. You could easily modify to accept extra parameters and return only nums, lowers, or caps. I don't think the ultra-compressed style is necessary while(s.length< L) s+= randomchar(); Jan 17, 2014 at 19:24
  • 3
    Also while(L--) will do it
    – vsync
    Jun 17, 2014 at 12:30
  • 3
    Better to use the more robust 'A'.charCodeAt(0) rather than the magic number 55 (and likewise for the 61). Particularly since, on my platform anyway, the magic number that returns is 65. That code will self-document better as well.
    – Grumdrig
    Jul 10, 2017 at 6:00
  • I created a minification optimized (46 bytes smaller) variant of your implementation here: stackoverflow.com/a/52412162
    – Waruyama
    Sep 20, 2018 at 7:18
75

Random String Generator (Alpha-Numeric | Alpha | Numeric)

/**
 * Pseudo-random string generator
 * http://stackoverflow.com/a/27872144/383904
 * Default: return a random alpha-numeric string
 * 
 * @param {Integer} len Desired length
 * @param {String} an Optional (alphanumeric), "a" (alpha), "n" (numeric)
 * @return {String}
 */
function randomString(len, an) {
  an = an && an.toLowerCase();
  var str = "",
    i = 0,
    min = an == "a" ? 10 : 0,
    max = an == "n" ? 10 : 62;
  for (; i++ < len;) {
    var r = Math.random() * (max - min) + min << 0;
    str += String.fromCharCode(r += r > 9 ? r < 36 ? 55 : 61 : 48);
  }
  return str;
}

console.log(randomString(10));      // i.e: "4Z8iNQag9v"
console.log(randomString(10, "a")); // i.e: "aUkZuHNcWw"
console.log(randomString(10, "n")); // i.e: "9055739230"


While the above uses additional checks for the desired A/N, A, N output, let's break it down the to the essentials (Alpha-Numeric only) for a better understanding:

  • Create a function that accepts an argument (desired length of the random String result)
  • Create an empty string like var str = ""; to concatenate random characters
  • Inside a loop create a rand index number from 0 to 61 (0..9+A..Z+a..z = 62)
  • Create a conditional logic to Adjust/fix rand (since it's 0..61) incrementing it by some number (see examples below) to get back the right CharCode number and the related Character.
  • Inside the loop concatenate to str a String.fromCharCode( incremented rand )

Let's picture the ASCII Character table ranges:

_____0....9______A..........Z______a..........z___________  Character
     | 10 |      |    26    |      |    26    |             Tot = 62 characters
    48....57    65..........90    97..........122           CharCode ranges

Math.floor( Math.random * 62 ) gives a range from 0..61 (what we need).
Let's fix the random to get the correct charCode ranges:

      |   rand   | charCode |  (0..61)rand += fix            = charCode ranges |
------+----------+----------+--------------------------------+-----------------+
0..9  |   0..9   |  48..57  |  rand += 48                    =     48..57      |
A..Z  |  10..35  |  65..90  |  rand += 55 /*  90-35 = 55 */  =     65..90      |
a..z  |  36..61  |  97..122 |  rand += 61 /* 122-61 = 61 */  =     97..122     |

The conditional operation logic from the table above:

   rand += rand>9 ? ( rand<36 ? 55 : 61 ) : 48 ;
// rand +=  true  ? (  true   ? 55 else 61 ) else 48 ;

From the explanation above, here's the resulting alpha-numeric snippet:

function randomString(len) {
  var str = "";                                // String result
  for (var i = 0; i < len; i++) {              // Loop `len` times
    var rand = Math.floor(Math.random() * 62); // random: 0..61
    var charCode = rand += rand > 9 ? (rand < 36 ? 55 : 61) : 48; // Get correct charCode
    str += String.fromCharCode(charCode);      // add Character to str
  }
  return str; // After all loops are done, return the concatenated string
}

console.log(randomString(10)); // i.e: "7GL9F0ne6t"

Or if you will:

const randomString = (n, r='') => {
  while (n--) r += String.fromCharCode((r=Math.random()*62|0, r+=r>9?(r<36?55:61):48));
  return r;
};

console.log(randomString(10))

1
  • 1
    For a reason I was not able to identify, x.toString(36) --- as is used in the above answers --- was not reliably generating the same characters when I compared the outputs of two apps that had different ES versions, and this function fixed this for me as it does not use .toString()! Feb 4, 2021 at 22:13
73

To meet requirement [a-zA-Z0-9] and length of 5 characters, use

For Browser:

btoa(Math.random().toString()).substring(10,15);

For NodeJS:

Buffer.from(Math.random().toString()).toString("base64").substring(10,15);

Lowercase letters, uppercase letters, and numbers will occur.

(it's typescript compatible)

7
  • 6
    I guess, Math.random() could lead to a base64-string with too few characters.
    – Leif
    Jun 25, 2018 at 7:57
  • Adding on @Leif comment, this will only generate numbers between 1-5 and only 19 out of 52 letters!(upper and lower case) To test just run it multiple time, Set it to see unique chars and then sort. one liner for that: [...new Set([...Array(100000)].map(()=>btoa(Math.random()).substr(5, 5)).join(""))].sort()
    – Or Duan
    Nov 14, 2020 at 7:19
  • Why do we need toString in the browser example? Jan 9, 2022 at 14:13
  • You're right. No need for toString(). But as I wanted to do something as "it's typescript compatible". So I left it that way. Jan 11, 2022 at 19:38
  • 1
    can we use .substing(10,15) instead?
    – nCoder
    Sep 27, 2022 at 17:47
45

The simplest way is:

(new Date%9e6).toString(36)

This generate random strings of 5 characters based on the current time. Example output is 4mtxj or 4mv90 or 4mwp1

The problem with this is that if you call it two times on the same second, it will generate the same string.

The safer way is:

(0|Math.random()*9e6).toString(36)

This will generate a random string of 4 or 5 characters, always diferent. Example output is like 30jzm or 1r591 or 4su1a

In both ways the first part generate a random number. The .toString(36) part cast the number to a base36 (alphadecimal) representation of it.

7
  • I'm not quite sure how this answers the question; This is a 7 year old question with many valid answers already. If you choose to provide a new answer, you should really take extra care to make sure that your answer is well explained and documented.
    – Claies
    Mar 11, 2015 at 22:01
  • 1
    If you use Date, why don't you just use it like: (+new Date).toString(36) Jul 15, 2015 at 13:47
  • 2
    I wanted a longish random string with a short-as-possible routine (for a code demo) that doesn't need to be cryptographically amazing, just produce some nice random visual "fluff". I like this answer the best (your 2nd one), so thank you. My two cents: I can beat it for shortness with one less keystroke, and it will typically produce 13 random characters (without a period): (Math.random()*1e20).toString(36). Feb 27, 2016 at 19:11
  • 1
    one qualm I have with this answer is that it will not use [A-Z] which happens to be in the original question. Oct 11, 2017 at 22:16
  • 1
    The "simplest way" doesn't create random strings at all; it creates highly predictable strings with the superficial appearance of being random. Aug 27, 2022 at 1:26
37

Here are some easy one liners. Change new Array(5) to set the length.

Including 0-9a-z

new Array(5).join().replace(/(.|$)/g, function(){return ((Math.random()*36)|0).toString(36);})

Including 0-9a-zA-Z

new Array(5).join().replace(/(.|$)/g, function(){return ((Math.random()*36)|0).toString(36)[Math.random()<.5?"toString":"toUpperCase"]();});

Codegolfed for ES6 (0-9a-z)

Array(5).fill().map(n=>(Math.random()*36|0).toString(36)).join('')
0
28

There is no best way to do this. You can do it any way you prefer, as long as the result suits your requirements. To illustrate, I've created many different examples, all which should provide the same end-result

Most other answers on this page ignore the upper-case character requirement.

Here is my fastest solution and most readable. It basically does the same as the accepted solution, except it is a bit faster.

function readableRandomStringMaker(length) {
  for (var s=''; s.length < length; s += 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.charAt(Math.random()*62|0));
  return s;
}
console.log(readableRandomStringMaker(length));
// e3cbN

Here is a compact, recursive version which is much less readable:

const compactRandomStringMaker = (length) => length-- && "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62|0) + (compactRandomStringMaker(length)||"");
console.log(compactRandomStringMaker(5));
// DVudj

A more compact one-liner:

Array(5).fill().map(()=>"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62)).join("")
// 12oEZ

A variation of the above:

"     ".replaceAll(" ",()=>"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62))

The most compact one-liner, but inefficient and unreadable - it adds random characters and removes illegal characters until length is l:

((l,f=(p='')=>p.length<l?f(p+String.fromCharCode(Math.random()*123).replace(/[^a-z0-9]/i,'')):p)=>f())(5)

A cryptographically secure version, which is wasting entropy for compactness, and is a waste regardless because the generated string is so short:

[...crypto.getRandomValues(new Uint8Array(999))].map((c)=>String.fromCharCode(c).replace(/[^a-z0-9]/i,'')).join("").substr(0,5)
// 8fzPq

Or, without the length-argument it is even shorter:

((f=(p='')=>p.length<5?f(p+String.fromCharCode(Math.random()*123).replace(/[^a-z0-9]/i,'')):p)=>f())()
// EV6c9

Then a bit more challenging - using a nameless recursive arrow function:

((l,s=((l)=>l--&&"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62|0)+(s(l)||""))) => s(l))(5);
// qzal4

This is a "magic" variable which provides a random character every time you access it:

const c = new class { [Symbol.toPrimitive]() { return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62|0) } };
console.log(c+c+c+c+c);
// AgMnz

A simpler variant of the above:

const c=()=>"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(Math.random()*62|0);
c()+c()+c()+c()+c();
// 6Qadw
26

I know everyone has got it right already, but i felt like having a go at this one in the most lightweight way possible(light on code, not CPU):

function rand(length, current) {
  current = current ? current : '';
  return length ? rand(--length, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".charAt(Math.floor(Math.random() * 60)) + current) : current;
}

console.log(rand(5));

It takes a bit of time to wrap your head around, but I think it really shows how awesome javascript's syntax is.

3
  • 23
    If you're trying to keep the code short, why write current = current ? current : ''; when you can write current = current || '';
    – CaffGeek
    Aug 8, 2011 at 13:45
  • 10
    since we're talking micro optimization here i would actually suggest to skip the variable assignment entirely if not necessary: current || (current = ''); Dec 13, 2013 at 10:36
  • Attempting micro optimization while using a "nice" but resource wasting recursive algorithm makes no sense :-) A for loop still is best in Javascript and beats recursion big time, until really big advances in the optimizing code of the runtimes are made.
    – Mörre
    Jun 26, 2019 at 9:52
25

Generate a secure random alphanumeric Base-62 string:

function generateUID(length)
{
    return window.btoa(String.fromCharCode(...window.crypto.getRandomValues(new Uint8Array(length * 2)))).replace(/[+/]/g, "").substring(0, length);
}

console.log(generateUID(22)); // "yFg3Upv2cE9cKOXd7hHwWp"
console.log(generateUID(5)); // "YQGzP"

19

In case anyone is interested in a one-liner (although not formatted as such for your convenience) that allocates the memory at once (but note that for small strings it really does not matter) here is how to do it:

Array.apply(0, Array(5)).map(function() {
    return (function(charset){
        return charset.charAt(Math.floor(Math.random() * charset.length))
    }('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'));
}).join('')

You can replace 5 by the length of the string you want. Thanks to @AriyaHidayat in this post for the solution to the map function not working on the sparse array created by Array(5).

1
  • 22
    Every javascript program is a 'one-liner' if you format it as such Dec 1, 2013 at 14:56
19

If you're using Lodash or Underscore:

var randomVal = _.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 5).join('');
2
  • 9
    Lodash uses _.sampleSize('asdfgh',5).join('')
    – marlo
    Aug 24, 2016 at 4:08
  • 5
    This actually is not a good solution, because per docs each character is from a unique index. That means it's not truly random, since no character can / will ever repeat. Nov 4, 2017 at 21:44
17
const c = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
const s = [...Array(5)].map(_ => c[~~(Math.random()*c.length)]).join('')
0
15

Here's the method I created.
It will create a string containing both uppercase and lowercase characters.
In addition I've included the function that will created an alphanumeric string too.

Working examples:
http://jsfiddle.net/greatbigmassive/vhsxs/ (alpha only)
http://jsfiddle.net/greatbigmassive/PJwg8/ (alphanumeric)

function randString(x){
    var s = "";
    while(s.length<x&&x>0){
        var r = Math.random();
        s+= String.fromCharCode(Math.floor(r*26) + (r>0.5?97:65));
    }
    return s;
}

Upgrade July 2015
This does the same thing but makes more sense and includes all letters.

var s = "";
while(s.length<x&&x>0){
    v = Math.random()<0.5?32:0;
    s += String.fromCharCode(Math.round(Math.random()*((122-v)-(97-v))+(97-v)));
}
2
  • With this function, you can never get an uppercase letter greater than 'M' or a lowercase letter lesser than 'n'. Jan 21, 2015 at 14:21
  • Really? ooh! will probably test it more then. Hmm, however, given it's a random string and we don't really care what letters are in it (as long as they are random) then it still does what we want it to do which is all that matters but yes, will provide an upgrade, thanks.
    – Adam
    Jul 27, 2015 at 11:50
15

One liner:

Array(15).fill(null).map(() => Math.random().toString(36).substr(2)).join('')
// Outputs: 0h61cbpw96y83qtnunwme5lxk1i70a6o5r5lckfcyh1dl9fffydcfxddd69ada9tu9jvqdx864xj1ul3wtfztmh2oz2vs3mv6ej0fe58ho1cftkjcuyl2lfkmxlwua83ibotxqc4guyuvrvtf60naob26t6swzpil
3
  • To make it shorter change argument in Array(15) to a smaller value. E.g.: Array(4).
    – iamarkadyt
    Apr 3, 2020 at 18:40
  • I really love this solution, simple and clear. It is generating 15 random numbers between 0 and 1, generate the hexadecimal, and then remove the first two chars. Finally it is merging all of them together.
    – Siscia
    May 11, 2020 at 20:17
  • erroneous solution, uppercase characters aren't generated. Jul 31, 2021 at 16:20
15

Improved @Andrew's answer above :

Array.from({ length : 1 }, () => Math.random().toString(36)[2]).join('');

Base 36 conversion of the random number is inconsistent, so selecting a single indice fixes that. You can change the length for a string with the exact length desired.

0
14

Assuming you use underscorejs it's possible to elegantly generate random string in just two lines:

var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var random = _.sample(possible, 5).join('');
1
  • 6
    This will make the returned value have all unique chars. Also, the length of the string is limited up to the the length of var possible.
    – Yefu
    Nov 21, 2016 at 1:37
14

Whilst this answer is almost similar to others, it differs in that it uses:

  • repeat to create 5 characters (can be generalized to n)
  • replace with regex /./g to replace those 5 characters
  • the formula is random pick a character from a 62 character A-Za-z0-9 string

let ans = "x".repeat(5)
             .replace(/./g, c => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[Math.floor(Math.random() * 62) ] );
console.log(ans);

13
function randomString (strLength, charSet) {
    var result = [];
    
    strLength = strLength || 5;
    charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    
    while (strLength--) { // (note, fixed typo)
        result.push(charSet.charAt(Math.floor(Math.random() * charSet.length)));
    }
    
    return result.join('');
}

This is as clean as it will get. It is fast too, http://jsperf.com/ay-random-string.

4
  • For me this always generates random strings with strLength - 1 :-/
    – AlexGrafe
    Nov 22, 2013 at 11:43
  • 4
    Switching from --strLength to strLength--fixes it for me.
    – AlexGrafe
    Nov 22, 2013 at 11:43
  • @Gajus I took the liberty of fixing the obvious typo. it is strLength-- postfix, not prefix.
    – Fattie
    May 5, 2022 at 17:31
  • thank you sir. Wrapping it in a func make it easy to copy/paste ❤️
    – Sagive
    Aug 6, 2022 at 9:24
11

Fast and improved algorithm. Does not guarantee uniform (see comments).

function getRandomId(length) {
    if (!length) {
        return '';
    }

    const possible =
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let array;

    if ('Uint8Array' in self && 'crypto' in self && length <= 65536) {
        array = new Uint8Array(length);
        self.crypto.getRandomValues(array);
    } else {
        array = new Array(length);

        for (let i = 0; i < length; i++) {
            array[i] = Math.floor(Math.random() * 62);
        }
    }

    let result = '';

    for (let i = 0; i < length; i++) {
        result += possible.charAt(array[i] % 62);
    }

    return result;
}
2
  • 4
    Great answer, but probability is not uniform. There are 62 possible characters and crypto.getRandomValues returns one of 256 unique values. Because 256 is not divided by 62, you end up having slightly higher probability of getting characters A-H. I think the best solution is to do what YouTube did, and just add 2 additional characters (possibly - and _) to the charset. Anyway, great work - this answer needs so much more love :)
    – TeWu
    May 19, 2017 at 12:07
  • adding - and _ is a great idea since it will get you the complete url-safe base64 set
    – cowbert
    Dec 14, 2017 at 23:55
10

How about this compact little trick?

var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var stringLength = 5;

function pickRandom() {
    return possible[Math.floor(Math.random() * possible.length)];
}

var randomString = Array.apply(null, Array(stringLength)).map(pickRandom).join('');

You need the Array.apply there to trick the empty array into being an array of undefineds.

If you're coding for ES2015, then building the array is a little simpler:

var randomString = Array.from({ length: stringLength }, pickRandom).join('');
10

You can loop through an array of items and recursively add them to a string variable, for instance if you wanted a random DNA sequence:

function randomDNA(len) {
  len = len || 100
  var nuc = new Array("A", "T", "C", "G")
  var i = 0
  var n = 0
  s = ''
  while (i <= len - 1) {
    n = Math.floor(Math.random() * 4)
    s += nuc[n]
    i++
  }
  return s
}

console.log(randomDNA(5));

10

Case Insensitive Alphanumeric Chars:

function randStr(len) {
  let s = '';
  while (s.length < len) s += Math.random().toString(36).substr(2, len - s.length);
  return s;
}

// usage
console.log(randStr(50));

The benefit of this function is that you can get different length random string and it ensures the length of the string.

Case Sensitive All Chars:

function randStr(len) {
  let s = '';
  while (len--) s += String.fromCodePoint(Math.floor(Math.random() * (126 - 33) + 33));
  return s;
}

// usage
console.log(randStr(50));

Custom Chars

function randStr(len, chars='abc123') {
  let s = '';
  while (len--) s += chars[Math.floor(Math.random() * chars.length)];
  return s;
}

// usage
console.log(randStr(50));
console.log(randStr(50, 'abc'));
console.log(randStr(50, 'aab')); // more a than b

1
  • This answer has fit more for my use case. It would be cool if you could add a var possible like in the accepted answer, so the outcome of the function is more configurable. Oct 11, 2018 at 11:40
9

The problem with responses to "I need random strings" questions (in whatever language) is practically every solution uses a flawed primary specification of string length. The questions themselves rarely reveal why the random strings are needed, but I would challenge you rarely need random strings of length, say 8. What you invariably need is some number of unique strings, for example, to use as identifiers for some purpose.

There are two leading ways to get strictly unique strings: deterministically (which is not random) and store/compare (which is onerous). What do we do? We give up the ghost. We go with probabilistic uniqueness instead. That is, we accept that there is some (however small) risk that our strings won't be unique. This is where understanding collision probability and entropy are helpful.

So I'll rephrase the invariable need as needing some number of strings with a small risk of repeat. As a concrete example, let's say you want to generate a potential of 5 million IDs. You don't want to store and compare each new string, and you want them to be random, so you accept some risk of repeat. As example, let's say a risk of less than 1 in a trillion chance of repeat. So what length of string do you need? Well, that question is underspecified as it depends on the characters used. But more importantly, it's misguided. What you need is a specification of the entropy of the strings, not their length. Entropy can be directly related to the probability of a repeat in some number of strings. String length can't.

And this is where a library like EntropyString can help. To generate random IDs that have less than 1 in a trillion chance of repeat in 5 million strings using entropy-string:

import {Random, Entropy} from 'entropy-string'

const random = new Random()
const bits = Entropy.bits(5e6, 1e12)

const string = random.string(bits)

"44hTNghjNHGGRHqH9"

entropy-string uses a character set with 32 characters by default. There are other predefined characters sets, and you can specify your own characters as well. For example, generating IDs with the same entropy as above but using hex characters:

import {Random, Entropy, charSet16} from './entropy-string'

const random = new Random(charSet16)
const bits = Entropy.bits(5e6, 1e12)

const string = random.string(bits)

"27b33372ade513715481f"

Note the difference in string length due to the difference in total number of characters in the character set used. The risk of repeat in the specified number of potential strings is the same. The string lengths are not. And best of all, the risk of repeat and the potential number of strings is explicit. No more guessing with string length.

1
  • Thanks! Your comment made me realize I shouldn't be generating IDs randomly. It looks like nanoid is much more popular than entropy-string and seems just as good for my purposes.
    – Altay_H
    Dec 4, 2020 at 23:18

Not the answer you're looking for? Browse other questions tagged or ask your own question.