Build a To-Do App with Node.js, Express, and Vanilla JavaScript

Computer Science

Build a To-Do App with Node.js, Express, and Vanilla JavaScript

JavaScriptNode.jsExpress

Build a To-Do App with Node.js, Express, and Vanilla JavaScript

Turn your existing HTML and CSS foundation into a small full-stack to-do app. You will add an Express server, connect browser interactions to a tiny API, and finish with a runnable app that can create, complete, delete, and filter tasks.

4 modules14 lessonsComputer ScienceJavaScriptNode.jsExpressHTMLCSSVanilla JavaScriptFetch APInpm

What you learn by building this

  • Create and run a minimal Node.js Express server
  • Serve an existing semantic HTML, CSS, and JavaScript frontend from Express
  • Design a small in-memory task data model and expose it through HTTP endpoints
  • Use browser fetch requests to load and modify tasks without reloading the page
  • Render task state, completion controls, deletion controls, and filters with vanilla JavaScript
  • Test the finished app through observable browser behavior and API responses

Learning Journey

1

Shape the project and run the server

3 lessons

Reuse the learner's existing semantic HTML and CSS strengths while introducing only the Node.js and Express runtime needed to make the project serve itself.

2

Build the task API

4 lessons

Add the smallest useful backend: an in-memory collection of tasks and predictable endpoints that the frontend can use.

3

Connect the browser to the API

3 lessons

Use familiar DOM work and targeted selectors to make the static page behave like a real application, with the browser and server sharing task state.

4

Make the app useful and shippable

4 lessons

Add the final user-facing behavior, then verify the complete workflow so the result is something the learner can confidently run and show.

Public lesson

Define the to-do app and organize its files

Lesson 3.1 — Give the to-do app a shape

You already know how to make semantic HTML and target it with CSS. This step is about deciding what the app must do and putting each responsibility in a place where you can find it later.

Work in your existing react-fullstack-app project. Keep your current HTML structure and styles; do not rebuild them from scratch.

Tasks

1. Write the first version of the app contract

Before creating files, decide what “done” means for the first version.

Create or update README.md with this checklist. Replace the bracketed text with your own wording where needed.

# To-do app

## Version 1 checklist

- [ ] Show the saved tasks when the page loads.
- [ ] Add a new task from the page.
- [ ] Mark a task as complete or incomplete.
- [ ] Delete a task.
- [ ] Save task changes so they remain after a restart.

## Task shape

Each task has:

- `id`: a unique value
- `title`: the text shown to the user
- `completed`: `true` or `false`

## Not in version 1

- [ ] Add your own feature that will wait until a later version.

Keep the first version small. For example, filtering, accounts, due dates, and categories can wait.

Tasks

Check: Read the checklist as a user story. Every item should describe something you could demonstrate in the browser, except the task shape and “not in version 1” notes.

Tasks

2. Create the project structure

Create this structure inside the project:

react-fullstack-app/
├── data/
│   └── tasks.json
├── public/
│   ├── index.html
│   ├── styles.css
│   └── app.js
├── server/
│   └── index.js
├── package.json
└── README.md

If your existing files have different names, keep the names that already make sense. The important separation is:

  • server/ — receives requests and reads or changes task data
  • public/ — the files the browser loads
  • data/ — saved task information
  • README.md — the feature contract

Tasks

Move or copy your existing semantic page into public/index.html and your existing CSS into public/styles.css. Keep the meaningful elements you already made, such as headings, labels, forms, lists, and buttons.

Tasks

Do not add JavaScript behavior yet. Leave the existing controls as markup until the app’s data flow is connected.

Tasks

Check: Open public/index.html directly in the browser. You should still see the same page structure and styling you had before. If the styling disappeared, fix the stylesheet path before continuing.

Tasks

3. Add starter task data

Create data/tasks.json with two or three tasks. Use realistic text that will make the later interface easy to recognize.

[
  {
    "id": "task-1",
    "title": "Replace this with a task you really want to track",
    "completed": false
  },
  {
    "id": "task-2",
    "title": "Add another task for testing",
    "completed": true
  }
]

Change the IDs and titles rather than keeping the placeholder wording. Keep completed as a Boolean: it must be either true or false, not a quoted string.

Tasks

Check: Parse the file with your editor’s JSON validation, or run the project’s available validation command. The file should contain one array with no red JSON errors. It should also contain at least one incomplete task and one completed task so both states can eventually be displayed.

Tasks

4. Give the server one clear starting point

Create server/index.js. This is only the server’s starting outline for now; leave the request behavior unfinished.

const express = require("express");
const path = require("path");

const app = express();
const port = /* choose the port your project will use */;

app.use(express.json());
app.use(express.static(path.join(__dirname, "..", "public")));

app.get("/api/tasks", (request, response) => {
  // Later: read the tasks from data/tasks.json.
});

app.listen(port, () => {
  console.log(`To-do app running on port ${port}`);
});

Choose the same port your project’s existing setup expects. Do not try to implement the API route yet; the purpose here is to make the boundary visible:

browser
   │ requests page or /api/tasks
server/index.js
   │ later reads and updates
data/tasks.json

The browser-facing files stay in public, while saved task information stays in data. That separation will keep the upcoming request code easier to reason about.

Tasks

Check: Start the server using the command already defined by your project. You should see the server’s startup message. Visit the local address in a browser and confirm that it serves your existing public/index.html.

Find the bug

Something's wrong — can you spot it?

If starting the server fails, check these in order:

  1. Is Express installed in the project?
  2. Does the port value contain a number?
  3. Is the server start command pointing to server/index.js?
  4. Is the stylesheet path relative to public/index.html?

Tasks

5. Compare the structure with the checklist

Look at each version 1 feature and point to the file that will eventually help deliver it:

FeatureMain place it will live
Show taskspublic/app.js + server/index.js
Add a taskpublic/index.html + public/app.js + server
Complete a taskpublic/app.js + server
Delete a taskpublic/app.js + server
Persist changesdata/tasks.json + server

This is a map, not an instruction to implement all five features now.

Tasks

Final check: Your project should now have:

  • a short version 1 checklist
  • semantic markup and CSS still visible in public
  • valid sample task data in data/tasks.json
  • a server entry file with an unfinished /api/tasks boundary
  • a local server that can serve the frontend

Stop here once the structure is working. The next lesson can give the server route a real job without forcing the browser, server, and data storage into one large file.

Course Outline

4 modules · 14 lessons

Shape the project and run the server

Build the task API

Connect the browser to the API

Make the app useful and shippable

Learn by building your own version.

Remix this public project to open the workspace, follow the guided build, and let the AI mentor teach you through the work instead of doing it for you.