UUID, short for Universal Unique Identifier, is a 128-bit value for representing entities on the internet. An entity can be data in any form. For example, NodeJS UUID can be a database instance or an object.
UUID is sometimes referred to as GUID (Global Unique Identifier). It has evolved so much that it is now the preferred way to generate IDs, despite the existence of other ways to do the same thing that you will learn in this tutorial.
Structure and Usage of NodeJS UUID
NodeJS UUIDs are generated by advanced algorithms, making it almost impossible for a collision to occur. Collision, also called duplication, is the generation of two UUIDs with the same characters.
UUID is hexadecimal, written in 32 characters of 4 hyphens, divided into groups of 8-4-4-4-12 characters. UUIDs occur in 3 variants: variant 0 (currently obsolete), variant 1 (used today), and variant 2 (reserved for Microsoft's backward compatibility).
Here is the summary of how to generate a unique ID with NodeJS.
// install
npm i uuid
// import
const uuid = require('uuid')
// usage
const uniqueRandomID = uuid.v4()
Apart from the (random UUID) version 4 (v4), you can use the following methods:
- NIL: A string of all zeros.
- parse: Generate an array of bytes from a UUID string.
- validate: Test if the given string is a valid UUID.
- stringify: Generate a UUID string from an array of bytes.
- v1: Generate a timestamp UUID.
- v3: Generate a namespace w/ MD5 UUID.
- v5: Generate a namespace w/ SHA-1 UUID.
Example-1: Log NodeJS UUIDs on the console.
The simplest way to view the NodeJS UUID result is to print it on the console. Here is an example.
const uuid = require('uuid')
const result = uuid.v4()
console.log(result)
I import the uuid
module and generate unique random IDs with the module's version four. Lastly, I log the result on the console.
I get the following output:
bf2741cc-3ab9-4e16-82dc-2ecbcbbc667b
Example-2: Print NodeJS UUIDs on a web page
The second way to constantly generate and view unique strings with NodeJS UUID is to import the modules,
const http = require('http')
const uuid = require('uuid')
const server = http.createServer( (req, res) => {
const data = uuid.v4()
if(req.url === '/'){
res.writeHead(200, 'text/html')
res.end(data)
}
})
I create a server with request req
and response res
objects using the createServer()
method of the HTTP module.
I then generate a random ID and store the result in the data variable. If the request comes from the home /
route, the server returns OK status 200
with a text or HTML file with a unique ID stored in the data variable. The server ends the response by sending, res.end()
, the data to the web page.
The server listens on port 5000 for subsequent requests.
const PORT = process.env.PORT || 5000
server.listen(PORT, console.log(`Server listens on port ${PORT}`))
Lastly, I start the server using nodemon
.
{
"name": "uuid",
"version": "1.0.0",
"description": "",
"main": "example-2.js",
"scripts": {
"start": "node example-2.js",
"dev": "nodemon example-2.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"express": "^4.18.1",
"nanoid": "^3.3.4",
"nodemon": "^2.0.16",
"uniqid": "^5.4.0",
"uuid": "^8.3.2"
}
}
Then navigate to the browser and check for the (unique ID) data on port 5000.
The browser outputs a unique ID every time the page gets refreshed. Let's now see a more helpful way to view the unique IDs.
Example-3: Save a unique ID to the database with AJAX
Assume you are registering users for an event. Apart from the username and email address, you want to assign them unique ticket numbers whenever they register for the event through an online form.
We can do that with a simple frontend and express server as follows.
1. Install packages
Head over to the terminal, create a folder for the project, and open it with a code editor.
Let's initialize an NPM package before installing NodeJS UUID, express (server), nodemon
(server restarting), and mongoose (connecting to MongoDB).
npm init -y
npm i express uuid nodemon mongoose
Next, configure node
to run the start
script. On the other hand, nodemon
runs the dev
script.
2. Create folders and files
models -> User.js
Create a models
folder then add a Users.js
file containing the user's database collection's blueprint to it.
const mongoose = require("mongoose")
const userSchema = new mongoose.Schema({
username: { type: String, required: true},
email: { type: String, required: true},
ticketNumber: { type: String, required: true}
})
module.exports = mongoose.model('User', userSchema)
Every new user will have a username, email, and ticket number. The ticket number, ticketNumber
, is the NodeJS UUID we create in the index.js file.
index.js
Create the application's entry file (index.js) and configure modules and routes.
// import the installed modules
const express = require("express")
const uuid = require('uuid')
//import user model and the database configuration
const User = require('./models/User')
const db = require('./db')
const app = express()
//run the database
db()
// receive requests (in json format) through the `index.html` file in the public folder.
app.use(express.static('public'))
app.use(express.json({ extended: false, limit: '2mb'}))
// routing
app.post('/api', async (req, res) => {
const ticketNumber = uuid.v4()
let user = new User({ username: req.body.username, email: req.body.email, ticketNumber})
try {
user = await user.save()
console.log(user);
} catch (error) {
console.log(error);
}
})
//listen for requests
const PORT = process.env.PORT || 3000
app.listen(PORT, console.log(`listening for connections on port ${PORT}`))
db.js
The db.js
file that we imported in the entry file stores user data in MongoDB running locally. I have named mine ticket.
const mongoose = require('mongoose')
const dbConnection = async () => {
try {
const conn = await mongoose.connect('mongodb://127.0.0.1:27017/ticket')
console.log(`db runs in ${conn.connection.host}`);
} catch (error) {
console.log(error);
process.exit(1)
}
}
module.exports = dbConnection
We confirm if the application runs in localhost, as we have configured it to do, by console-logging the host connection. Else, it will catch the error.
public -> index.html, script.js
The index.html
file in the public folder collects username and email and sends them to the script.js
file. We style the forms with Bootstrap 5.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<!-- JavaScript Bundle with Popper -->
<script defer src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
<title>Ticket registration</title>
<script src="./script.js" defer></script>
</head>
<body>
<div class="container my-3 w-75 mx-auto">
<div class="mb-3">
<label for="username" class="form-label">Name: </label>
<input type="text" class="form-control" id="username" maxlength="30" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email address: </label>
<input type="email" class="form-control" id="email" maxlength="30" required>
</div>
<button id="btn" class="btn btn-primary">Submit</button>
</div>
</body>
</html>
The script.js
sends the username and email to the /api
endpoint for saving to the database.
// grab the username, email and button with respective IDs.
const username = document.getElementById('username')
const email = document.getElementById('email')
const btn = document.getElementById('btn')
// send the data to /api endpoint on button click.
btn.addEventListener('click', async () => {
if(username.value === '' || email.value === '') return
const data = { username: username.value, email: email.value }
username.value = ''
email.value = ''
await fetch('/api', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
})
We clear the form after the first form submission to avoid saving email and username duplicates. Likewise, the button should not empty values.
We then store the details in the data object and posts them with the fetch API.
At the /api
route, the application creates a random NodeJS UUID and stores the result in ticketNumber
. We create a new user with the request body's username, and email, plus the ticket number ticketNumber
. If the data gets saved to the database, we log the (user) result on the console.
3. Start the server
Return to the terminal and start the server.
npm run dev
Head over to the browser, localhost:3000
to open the application, and send the user details for saving. Type your details.
Then click the submit button, closely watching what happens at the backend terminal. No sooner than we hit submit than the terminal printed the user details. More excitingly, the ticketNumber
column is the NodeJS UUID that we expected.
We can confirm the details we saved by comparing the logged results with Mongo Shell's. And yes, there is a match!
Now that you know how to generate a unique ID with NodeJS UUID let's see how to do a similar thing with the crypto
, uniqid
, and nanoid
modules and the Math
object.
Alternatives to the NodeJS UUID Module
1. The Crypto module
The crypto module is one of the most secure and scalable ways to generate unique and cryptographically pseudo-random solid data. It wraps the OpenSSL cryptographic functions, making it possible to do many Node.js security-related roles such as hash calculations and authentications.
It avails options for generating unique IDs in Node.js. Here are a few examples.
1.1: The randomUUID method
As the name suggests, this method outputs random IDs.
const { randomUUID } = require('crypto');
console.log(randomUUID())
1.2: The randomBytes method
The randomBytes()
method lets you specify the number of bytes to generate.
crypto.randomBytes(128, (err, buf) => {
if (err) throw err;
console.log(`${buf.length} bytes of random data: unique random ID ${buf.toString('hex')}`)
})
For example, you can generate random, unique bytes of 128 characters by asynchronously running the randomBytes()
method.
We specify the byte length followed by a callback function containing the error and (buffer) data. If the process fails, the system throws an error. Otherwise, we log the result (of 128 bytes, converted to a string) to the console.
2. The uniqid module
It generates unique IDs based on the machine name, process, or current time.
The advantage of the uniqid
module is that it is fast and generates unique IDs even if the instance is run simultaneously on multiple machines and processes.
const uniqid = require('uniqid')
// unique IDs despite running an instance at the same time
console.log(uniqid(), uniqid())
// Introduce suffixes and prefixes
console.log(uniqid(79, 2022))
// 8 byte id depending on the current time
console.log(uniqid.time())
3. The nanoid module
The nanoid module is more secure than the uniqid
module that persists certain characters for subsequent output. The module is only 130 bytes and runs faster than NodeJS UUID.
const { nanoid } = require('nanoid')
console.log(nanoid())
4. The Math object
Finally, you can use the Math object to generate random unique IDs with NodeJS.
const randomID = Math.random().toString(30).slice(2)
console.log(randomID)
The string input must be an integer ranging between 2 and 36.
Its main drawback is that it is cryptographically insecure. However, you can improve the security of the IDs by combining the Math object with the crypto module's one of the methods.
const { randomBytes } = require('crypto')
const uniqueUD = Math.random().toString(36).slice(2) + randomBytes(8).toString('hex') + new Date().getTime()
console.log(uniqueUD)
Conclusion
NodeJS UUID lets you generate unique IDs. Besides, you can apply its alternatives as illustrated in this tutorial.