Build a Todo App: Full Walkthrough for Beginners and Pros

Build a Todo App with React and Node JS Full Walkthrough for Beginners and Full Stack Learners

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?

"When developers ask where to begin full-stack development, I always recommend starting by building a Todo App. It's practical, repeatable, and teaches REST APIs, CRUD, and component-based UI — all in one go."
— 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

🏠

Click here to Read more Like this Post

Post a Comment

Previous Post Next Post