Creating a to-do list application using Node.js involves setting up an Express server, creating RESTful APIs for CRUD operations, and using a database to store tasks. Enhance functionality with features like task prioritization and deadlines.
Prerequisites:
Features
- Dynamic Frontend, through EJS, which is an NPM package.
- Backend built with Nodejs.
- Database Used: MongoDB Atlas.
How the application works
- A home page is rendered where the user can see his tasks and also insert a new task.
- A new request is sent to the server-side when we click on add button.
- A new request for deleting the item is sent when we check it, once the task is completed.
Note: This article will focus mainly on the backend, thus detailed explanations for the frontend part, i.e., HTML and CSS will not be given, although code will be provided.Â
Let's start with step by step implementation.
Steps to Implement To-Do List using Node
Step 1: Open an empty folder in VS Code. Create a file with the name index.js inside this folder.Â
Step 2:Â Write the following command in the terminal, to initialize this folder for making a Nodejs project.
npm init
Step 3:Â After this, write the following command to install some packages that we will be using in our application:
npm install --save express ejs body-parser mongodb mongoose
Now create two folders beside our app.js, Name them as public ( for files we want to display to the user ) and views( for EJS files ).
Project Structure:
It will look like the following.

The updated dependencies in the package.json file
"dependencies": {
"body-parser": "^1.20.2",
"ejs": "^3.1.10",
"express": "^4.19.2",
"mongodb": "^6.7.0",
"mongoose": "^8.4.3"
}
Step 4: In index.js, code the server to handle GET and POST requests, manage data, define the server port, connect to a cloud database, and contain all application logic.
Node
// index.js
// To use the packages installed, we import
// them using require and save them in
// a constant
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
// Initializing a constant to use express
// methods and create middlewares.
const app = express();
// Telling Node.js to use body-parser for
// reading data coming from our
// incoming requests in URL
app.use(bodyParser.urlencoded({ extended: true }));
// Telling Nodejs that all our static
// files(here: CSS files) are
// stored in public folder
app.use(express.static("public"));
// Telling Nodejs that we will write our
// frontend in ejs files. Thus viewing
// engine has to be set to use ejs
app.set("view engine", "ejs");
Note: We don't require mongodb, as it is taken care of by mongoose.
Step 5:Â Now we are going to connect our application with the cloud database, MongoDB Atlas and define the basic structure of our collection. We define what is the type of data we store and other features associated with it.
Node
// index.js
// Make sure you did not use any special
// characters(e.g. @) in your user-name
// or password
mongoose.connect(
"mongodb+srv://<name>:<password>@cluster0.38u1b.mongodb.net/todoDB");
// Defining the schema or structure of
// a single item in mongodb
const taskSchema = {
name: {
type: String,
required: true
}
};
// Using the following code, node.js
// creates a collection named
// 'tasks' using the taskSchema
const Task = mongoose.model("Task", taskSchema);
Explanation: Use Mongoose to connect to the database, define an item blueprint with String type, and create a collection named "items." The "todoDB" in the URL is the database name, customizable as desired.
The URL for our database is received through the following steps from our MongoDB Atlas account:
- Click on the Connect Button.

- Choose the second Option: Connect your Application.


Step 6:Â We handle the request for our homepage at URL "/". This code serves our homepage, displaying all tasks. In this application, it's the only webpage needed, showcasing all tasks.
Node
// index.js
app.get("/", function (req, res) {
// Getting today's date to display
// on top of our to-do
let today = new Date();
let options = {
weekday: "long",
day: "numeric",
month: "long"
};
// If we do not use the first argument
// in below line, which is "en-US" we get
// date in form of numbers only, separated
// with a /, thus the day won't be known
let day = today.toLocaleDateString("en-US", options);
// Find is a function given by mongoose, which
// is applied to a collection, it returns
// all the documents found in it.
Task.find({}, function (err, foundTasks) {
if (err) {
console.log(err)
}
else {
// Render the file names index.ejs and
// send the object to with the following
// data, sent as second parameter, in
// which we send date
// and tasks found in database.
res.render("index", { today: day, tasks: foundTasks });
}
})
});
Explanation: When our application URL is typed in the browser, a GET request is sent to the "/" route, reading and viewing the homepage content. `app.get()` runs the callback for GET requests on "/". The `find` method from Mongoose retrieves all documents in the collection. If successful, it returns an array of objects. We then call the `render` function on the response object to send an EJS file and values to the frontend.
Step 7:Â Create an `index.ejs` file in the "views" folder. This file defines the webpage structure using HTML. It includes JavaScript logic for dynamic rendering, allowing new tasks to appear without reloading the page.
HTML
<!-- index.ejs -->
<!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">
<title>To-do List</title>
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
<div class="box" id="heading">
<h1 style="color: #ffffff">
<%= today %>
</h1>
</div>
<div class="box">
<!-- We check if the object receieved is not
empty, else there will be an error -->
<!-- To avoid error, we simply use if-else,
empty object is handled in if block -->
<% if (tasks.length===0) {%>
<p style="text-align: center;">
No Task Added Yet
</p>
<% } else { %>
<% for (var i=0; i< tasks.length; i++){ %>
<!-- Action is the route to which form
send request -->
<!-- And method defines the "type" of request -->
<form action="/delete" method="post">
<div class="item">
<input type="checkbox" name="checkbox"
value="<%=tasks[i]._id%>"
onchange="this.form.submit()">
<p>
<%= tasks[i].name %>
</p>
</div>
<hr>
</form>
<% } %>
<% } %>
<!-- Action is the route to which form
send request -->
<!-- And method defines the "type"
of request -->
<form class="item " action="/" method="POST">
<input type="text" name="newTask"
autocomplete="off"
placeholder="Add a New Task Here">
<button type="submit" name="submit">+</button>
</form>
</div>
</body>
</html>
Explanation: EJS syntax resembles HTML but allows JavaScript within <% %> and variables in <%= %>. It enables dynamic rendering by looping through received arrays to display items with checkboxes for deletion using MongoDB's _id.
NOTE: Make sure that the name of the variable matches the key of the object sent to the frontend from Nodejs while rendering ejs.
Step 8:Â In styles.css file, we write our CSS code, which gives a good look to our homepage. It makes the main container and heading of our page appear in the center, we define color themes we want to use and also style our font, button, and other elements on our page.
CSS
/* styles.css */
*{
font-family: cursive;
box-sizing: border-box;
}
h1 {
padding: 10px;
}
.box {
max-width: 450px;
margin: 20px auto;
background: white;
border-radius: 5px;
box-shadow: 7px 7px 15px 5px rgba(0, 0, 0, 0.3);
}
#heading {
background-color: #353434;
text-align: center;
}
.item {
min-height: 70px;
display: flex;
align-items: center;
border-bottom: 1px solid #F1F1F1;
}
.item:last-child {
border-bottom: 0;
}
input:checked+p {
text-decoration: line-through;
text-decoration-color: #353434;
}
input[type="checkbox"] {
appearance: none;
margin: 20px;
height: 25px;
width: 25px;
border: 2px solid black;
border-radius: 3px;
}
input[type="checkbox"]:hover,
input[type="checkbox"]:focus{
transform: scale(1.2);
background-color: #353434;
color: white;
cursor: pointer;
}
input[type="checkbox"]:checked{
clip-path: polygon(14% 44%, 0 65%,
50% 100%, 100% 16%, 80% 0%, 43% 62%);
}
p {
text-align: left;
margin: 0;
padding: 20px;
font-size: 1.8rem;
font-weight: bold;
color: #353434;
text-shadow: 2px 2px gray;
}
form {
text-align: center;
padding: 10px;
}
button {
width: 50px;
height: 50px;
border-radius: 50%;
font-size: 1.5rem;
background-color: #494848;
border-top: 4px solid white;
border-left: 4px solid white;
border-bottom: 4px solid black;
border-right: 4px solid black;
color: white;
}
button:hover{
cursor: pointer;
color: #494848;
background-color: white;
border: 3px solid #494848;
box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.459);
}
input[type="text"] {
margin: 5px;
text-align: center;
height: 50px;
background: transparent;
font-size: 20px;
font-weight: 200;
width: 100%;
border: none;
border-bottom: 4px solid #494848;
}
input[type="text"]:focus {
outline: none;
border: 2px solid #494848;
border-bottom: 4px solid #494848;
border-radius: 5px;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.301);
}
Step 9:Â Now we work on the routes to add an item. We are back to our index.js file. Now we will write the code that reads incoming data from the frontend, saves it in the database as a new task, then redirects back to the home page once the task is successfully added. We also check if the incoming data, here task, is not empty.
Node
// index.js
app.post("/", function (req, res) {
const taskName = req.body.newTask;
if (taskName) {
const task = new Task({
name: taskName,
});
// Save the task using save method provided
// by mongoose. It returns a promise, in
// which we re-direct to home page. we write
// it in then block to make sure that
// we are redirected only when the save
// method finished executing without any
// error. Otherwise the item will be saved,
// after we were redirected, thus, it will look
// like the task was not added and thus we
// will have to reload to see the newly added
// task. Which can be exhausting.
task.save()
.then(() => {
res.redirect("/");
});
} else {
res.redirect("/");
}
});
Explanation:In this process, we create a document from a collection akin to making an object from a class. Using `new`, we instantiate and `save()` the `itemName` to our MongoDB database. Conditional checks ensure the item isn't empty; upon saving, a redirect refreshes the homepage, triggering dynamic updates through Node.js middleware.
Step 10:Â For the delete request, clicking a checkbox triggers a form submission, sending the task's ID to delete. Node.js reads this ID, finds and deletes the corresponding task from the database, then redirects to the homepage upon completion.
Node
// index.js
app.post("/delete", function (req, res) {
const checkedItemId = req.body.checkbox;
Task.findByIdAndRemove(checkedItemId, function (err) {
if (!err) {
console.log("Successfully deleted checked item.");
res.redirect("/");
}
});
});
Explanation: In the form's action attribute, we specify "/delete" as the endpoint for the POST request. When the checkbox is clicked, the form submits, triggering app.post(). Using Mongoose, we find and delete the document matching the received ID from the items collection, executing a callback upon deletion.
Step 11:Â Finally, we write a code that makes our application accessible from one of the ports of the machine. It is called listening.
Node
app.listen(process.env.PORT || 3000, function () {
console.log("Server running at port 3000");
});
Explanation: At the end, we use app.listen() to start our server on port 3000. Alternatively, process.env.PORT accommodates the hosting service's port. It needn't match our development port.
Now let's see the complete code.
Node
// index.js
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const mongoose = require("mongoose");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));
mongoose.connect(
"mongodb+srv://<username>:<password>@cluster0.g6nae.mongodb.net/todolistDB");
const taskSchema = {
name: {
type: String,
required: true
}
};
const Task = mongoose.model("Task", taskSchema);
app.set("view engine", "ejs");
app.get("/", function (req, res) {
let today = new Date();
let options = { weekday: "long", day: "numeric", month: "long" };
let day = today.toLocaleDateString("en-US", options);
Task.find({}, function(err, foundTasks){
if (err){
console.log(err)
}
else {
res.render("index", { today: day, tasks: foundTasks });
}
})
});
app.post("/", function (req, res) {
const taskName = req.body.newTask;
if(taskName){
const task = new Task({
name: taskName,
});
task.save().then(()=>{
res.redirect("/");
});
} else{
res.redirect("/");
}
});
app.post("/delete", function (req, res) {
const checkedItemId = req.body.checkbox;
Task.findByIdAndRemove(checkedItemId, function (err) {
if (!err) {
console.log("Successfully deleted checked item.");
res.redirect("/");
}
});
});
app.listen(process.env.PORT || 3000, function () {
console.log("Server running at port 3000");
});
Step to run the application: To run the application, open the terminal and write the command.
node index.js
Output: Open browser and in its URL address box, write: localhost:3000.

Now let's understand how to deploy the above-created app.
Steps to Deploy Do-To Application
Step 1: Go to the website of Heroku. http://www.heroku.com/

Step 2: Sign Up if you don't already have an account.

Step 3: Fill in the SignUp Form

After Sing Up is complete, you will see a page like this:

You get a Get Started Page:

Step 4: Install Heroku CLI according to your Operating System:

Step 5: Open CLI of your system, or VS Code terminal in the current project directory. Login to Heroku using the terminal command:
heroku login

Step 6: A browser window opens, click on the login button and you are done.

Note: Since we just created an account and have Heroku open in our browser, it recognizes us and does not ask for credentials to log in. If we were logged out from the browser as well, then it would ask for email and password and then log us in.
Step 7: Then initialize git in our project. (make sure you have git installed in your computer system: https://git-scm.com/downloads): Write the command.
git init

Step 8: Add a .gitignore file and a Procfile using the following commands:
touch .gitignore
.gitignore file is created to list all the files and folders that should not be included in our repository. These are mainly node_modules folder, as it can be created anywhere by writing the command: npm install. This command reads the packages.json file and packages-lock.json file which hold the information of packages installed and installs in the directory automatically.
Step 9: Now in the terminal, write the following command.
heroku create

git add .

git commit -m "Initial Commit"

git push heroku master

Step 10: A URL will appear, that is the URL of your hosted application.

Link of deployed application: Â https://thawing-ravine-87998.herokuapp.com/
Similar Reads
How to Post Data in MongoDB Using NodeJS?
In this tutorial, we will go through the process of creating a simple Node.js application that allows us to post data to a MongoDB database. Here we will use Express.js for the server framework and Mongoose for interacting with MongoDB. And also we use the Ejs for our front end to render the simple
5 min read
How to Build Library Management System Using NodeJS?
A Library Management System is an essential application for managing books, users, and transactions in a library. It involves adding, removing, updating, and viewing books and managing users. In this article, we will walk through how to build a simple Library Management System using NodeJS. What We
6 min read
How to Install NodeJS on MacOS
Node.js is a popular JavaScript runtime used for building server-side applications. Itâs cross-platform and works seamlessly on macOS, Windows, and Linux systems. In this article, we'll guide you through the process of installing Node.js on your macOS system. What is Node.jsNode.js is an open-source
7 min read
How to Add Two Numbers in Console using Node.js ?
Adding two numbers using Node.js is a basic task that helps in understanding how to handle user input and process data within the Node.js environment. By following the steps in this guide, you'll learn how to create a simple Node.js application that reads numbers from the console, performs an additi
2 min read
How to Build User Management System Using NodeJS?
A User Management System is an essential application for handling user accounts and information. It involves creating, reading, updating, and deleting user accounts, also known as CRUD operations. In this article, we will walk through how to build a simple User Management System using NodeJS. What W
6 min read
How to build Hostel Management System using Node.js ?
In this article, we are going to create a Hostel Management System. A Hostel Management System is used to manage the record of students of a college to which the college provides a hostel, where a college can view all the student data including their names, roll number, date of birth, city, phone nu
9 min read
How to Send Email using NodeJS?
Sending emails programmatically is a common requirement in many applications, especially for user notifications, order confirmations, password resets, and newsletters. In this article, we will learn how to build a simple email-sending system using NodeJS. We will use Nodemailer, a popular module for
5 min read
How to create To-Do List using jQuery?
This article focuses on developing a To-do List with some basic features like: Add Task Delete Task Cross the completed tasks Prerequisites: Basic knowledge of Front-end development using HTML, CSS, JS, jQuery & Bootstrap-3. Steps: Initialize the layout: - Add a input text-box with a button to a
4 min read
How to Build Employee Management System using Node.js ?
An Employee Management System (EMS) is a crucial tool for businesses to efficiently manage their workforce. It allows companies to handle tasks like displaying employee details, adding new employees, removing existing ones, promoting employees, and updating salaries. In this article, we'll walk thro
8 min read
How to Build Hospital Management System using Node.js?
In this article, we are going to create a Hospital Management System. A Hospital Management System is basically used to manage patients in the hospital. It is helpful to see which patients do not have a bed allotted or if there are any free beds or not. It makes sure that the discharged patients' be
7 min read