Have you ever wondered how real-time apps like chat apps and online games are built? If you’ve never built one before, read this tutorial as I’m going to show you how to build a simple one using

What are we going to build?

It’s a simple app with one button and a label below it. The label displays “Likes: X” (where x is the current number of likes). When the user clicks on the button, the number of likes increases by one.

We’re going to make it real time by showing users on the app how the number of likes increases as other users are clicking on the button. So you don’t need to reload the page to see the latest value.

Here’s how the app would look like:

You can get the source code of this project on GitHub.

Creating a new project

In a new folder, add package.json using npm init -y, and then install these three packages:

npm install express ejs

We’ll use ejs as the templating engine, and for making our app a real-time app.

Displaying a hello world page

As mentioned above, we’ll use ejs for rendering our views. So create index.ejs and add the following:

  Realtime like app

  Hello World!

Now let’s create our node server and serve the above file as the homepage.

So create node.js and add this:

const app = require('express')()
const path = require('path')

app.engine('html', require('ejs').renderFile)
app.set('view engine', 'html')

app.get('/', (req, res) => {
  res.render(path.join(__dirname   '/index.ejs'), null, (err, html) => {

app.listen(3000, () => console.log('the app is running on localhost:3000'))

So we created a new server that runs on port 3000. When the user hits http://localhost:3000/ in the browser, we’ll render index.ejs and display it.

If you run the app using node index.js (or using nodemon if you want the app to restart automatically on changes) and open http://localhost:3000/, you should see “Hello World!” displayed.

Adding style.css

This isn’t a CSS tutorial, so let’s quickly add style.css in the root directory and fill it with this:

body {
  background: hsl(0, 50%, 80%);
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;
  padding: 0;

button {
  background: hsl(0, 50%, 90%);
  border: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 150px;
  height: 150px;
  cursor: pointer;
  outline: none;
  box-shadow: 0 14px 28px hsla(0, 50%, 10%, 25%), 0 10px 10px hsla(0, 50%, 10%, 22%);
  transition: all 0.3s cubic-bezier(.25,.8,.25,1);

button:hover {
  box-shadow: 0 1px 3px hsla(0, 50%, 10%, 12%), 0 1px 2px hsla(0, 50%, 10%, 24%);

button:active {
  box-shadow: none;

svg path {
  fill: hsl(0, 30%, 30%);

.main {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;

.likes {
  margin-top: 20px;
  color: hsl(0, 60%, 20%);
  font-weight: bold;
  font-family: sans-serif;
  text-transform: uppercase;
  font-size: 20px;

Now let’s tell our server about it so when we request it, it responds with this file.

Add this route in index.js (below the root route):

app.get('/style.css', (req, res) => {
  res.sendFile(path.join(__dirname   '/style.css'))

And then let’s use it in our index.ejs by adding this at the bottom of :

Displaying the button and the label

Open index.ejs and update it like this:

  Realtime like app


For this to work, we have to pass likes from the server when rendering the template.

So open index.js and update the root route like this:

let likes = 0

app.get('/', (req, res) => {
  res.render(path.join(__dirname   '/index.ejs'), { likes }, (err, html) => {

Note how we defined likes above it.

To keep this example simple, we defined likes in the memory, which means its value will go back to 0 when the server restarts. Typically in real-world apps you’ll have your data stored in the database.

Incrementing likes by clicking on the button

To do so, we need to add a new route that increments likes and returns the new value. And then we’ll make a request to this endpoint from index.ejs, when the user clicks on the button.

Let’s define the route first, in index.js.'/like', (req, res) => {
  res.json({ likes })

So it’s a POST endpoint at /like.

Now let’s listen for the button’s click event and send this request using the Fetch API.

Add the following above :

The app is now ready to be used but without showing the updated value in realtime. So if you open the app in multiple browser windows and try to update one, you won’t see the value updated in realtime on other browser windows until you reload them.

Making it a real-time app isn’t the only way to build real-time apps but it’s the most popular one. Not only that, but it’s also very good and easy to use.

We’ve already installed, so let’s initialize it.

But before I show you how, note that is composed of two parts:

  1. The server that we integrate with node http server.
  2. The client library that we use on the browser to communicate with the server part.

To initialize the server part, open index.js and update the top part like this:

const app = require('express')()
const http = require('http').createServer(app)
const path = require('path')
const io = require('')(http)

So we imported and passed it the http server object.

Now let’s use the http object to run the server instead of app.

http.listen(3000, () => console.log('the app is running on localhost:3000'))

With that, is initialized on the server!

When is initialized it exposes / endpoint. This endpoint contains the JS file that we’ll use in the browser to connect with (So it’s the’s client library.)

Go to index.ejs and include that file above the

After you add this, you should have the io object exposed globally on the browser (check that from the console).

To connect the browser to the server, just call io() and store the returned socket in a variable.

So put the following at the top of your , add this:

socket.on('likes:update', likes => {
  likesOutput.textContent = `Likes: ${likes}`

That's it! Now our app is completely a real-time app!

If your code is not working, compare it with the source code of this demo on GitHub to make sure you haven't forgotten anything.