Introduction: Why Build a Todo App?
Creating a Todo App is one of the most practical ways to learn full-stack development. Whether you're new to web development or brushing up your skills, this project combines key technologies like HTML, CSS, JavaScript, Node.js, and MongoDB into one functional and responsive application.
🎯 Goal: Learn to Build a Todo App with a fully functional backend and sleek frontend UI that works across devices.
Prerequisites
Before you begin, make sure you’ve installed:
-
Node.js & npm
-
MongoDB (local or Atlas cloud)
-
Basic knowledge of JavaScript, HTML, and CSS
-
A code editor like VS Code
Project Overview: Build a Todo App from Scratch
We’ll split the process into the following stages:
✅ Backend Setup
🧑🎨 Frontend User Interface
🛠 Integration & Deployment
📱 Responsive Design Tips
🧠 Expert Advice
✅ Backend Setup Using Node.js and Express
Let’s start by setting up a basic Express server and API routes.
1. Initialise the Project
mkdir todo-app
cd todo-app
npm init -y
npm install express mongoose cors dotenv
Create a .env
file for storing your MongoDB connection string:
MONGO_URI=mongodb://localhost:27017/todoDB
PORT=5000
2. Build the Express Server
Create a file named server.js
:
const express = require('express');
const mongoose = require('mongoose');
require('dotenv').config();
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
app.listen(process.env.PORT, () => {
console.log(`Server running on port ${process.env.PORT}`);
});
3. Create the Todo Model
const mongoose = require('mongoose');
const TodoSchema = new mongoose.Schema({
task: { type: String, required: true },
completed: { type: Boolean, default: false },
});
module.exports = mongoose.model('Todo', TodoSchema);
4. API Routes
Add a routes/todo.js
:
const express = require('express');
const router = express.Router();
const Todo = require('../models/Todo');
// Create
router.post('/add', async (req, res) => {
const newTask = new Todo(req.body);
await newTask.save();
res.json(newTask);
});
// Read
router.get('/', async (req, res) => {
const todos = await Todo.find();
res.json(todos);
});
// Update
router.put('/update/:id', async (req, res) => {
const todo = await Todo.findByIdAndUpdate(req.params.id, req.body, { new: true });
res.json(todo);
});
// Delete
router.delete('/delete/:id', async (req, res) => {
await Todo.findByIdAndDelete(req.params.id);
res.json({ message: "Todo deleted" });
});
module.exports = router;
Connect it in server.js
:
const todoRoutes = require('./routes/todo');
app.use('/api/todos', todoRoutes);
🧑🎨 Frontend UI with HTML, CSS, JavaScript (or React)
Let’s go with React for a dynamic and scalable UI.
1. Create React App
npx create-react-app client
cd client
npm install axios
2. Todo Component (client/src/components/TodoApp.jsx)
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const TodoApp = () => {
const [task, setTask] = useState('');
const [todos, setTodos] = useState([]);
const fetchTodos = async () => {
const res = await axios.get('/api/todos');
setTodos(res.data);
};
const addTodo = async () => {
await axios.post('/api/todos/add', { task });
setTask('');
fetchTodos();
};
const deleteTodo = async (id) => {
await axios.delete(`/api/todos/delete/${id}`);
fetchTodos();
};
useEffect(() => {
fetchTodos();
}, []);
return (
<div className="todo-container">
<h1>Todo App</h1>
<input value={task} onChange={e => setTask(e.target.value)} />
<button onClick={addTodo}>Add</button>
<ul>
{todos.map(todo => (
<li key={todo._id}>
{todo.task}
<button onClick={() => deleteTodo(todo._id)}>❌</button>
</li>
))}
</ul>
</div>
);
};
export default TodoApp;
📱 Responsive UI Design with CSS
Place this in App.css
:
.todo-container {
max-width: 600px;
margin: auto;
text-align: center;
padding: 20px;
}
input {
width: 70%;
padding: 10px;
margin-right: 10px;
}
button {
padding: 10px;
cursor: pointer;
}
@media (max-width: 600px) {
input {
width: 60%;
}
button {
padding: 8px;
}
}
🛠 Integration and Deployment
Connect Backend & Frontend
In client/package.json
, add:
"proxy": "http://localhost:5000"
Then run:
# In one terminal
npm start
# In another terminal
cd client && npm start
Deploy on Render or Vercel
-
Deploy backend on Render
-
Deploy frontend on Vercel
-
Use environment variables to connect MongoDB securely
🧠 Expert Advice: Why Build a Todo App?
— Meera Joshi, Senior Developer at DevCraft
Using a Todo App as a learning base helps not only in coding but also in understanding software architecture and user flow.
📌 Tips for Scalability
-
Add user authentication (JWT or OAuth)
-
Integrate drag and drop using libraries like
react-beautiful-dnd
-
Save tasks to localStorage if offline
-
Add a calendar view for due dates
✅ Recap
-
✅ Created REST API with Node.js + MongoDB
-
✅ Designed responsive UI in React
-
✅ Integrated backend and frontend
-
✅ Followed best practices in responsive design
-
✅ Ready for deployment