Unit 6 Project: Tiny Flask Notes App

Assemble routes, templates, forms, and validation

Intermediate 13 min

In this lesson

In this project you’ll build a small Flask notes app in Python: a page that lists notes and a form that adds one. You’ll see the full Flask shape, then focus on the part worth testing — the pure logic for adding and rendering notes, kept separate from the routes so it’s easy to reason about.

Explain it like I’m 5

A notes app is a page that shows a list and a form that adds one more item to that list. Add a note, it appears; restart the server with no storage, and the list starts empty again.

The whole app, end to end

Two routes do the work: / shows the notes, and /add receives the form and stores a new one. The notes live in a plain list in memory — simple to start with, and enough to learn the flow.

Example
# app.py
from flask import Flask, request, redirect, render_template

app = Flask(__name__)
notes = []   # in-memory; resets when the server restarts

@app.route("/")
def index():
    return render_template("index.html", notes=notes)

@app.route("/add", methods=["POST"])
def add():
    note = request.form.get("note", "").strip()
    if note:
        notes.append(note)
    return redirect("/")
List on /, add on /add, then redirect back to the list.

Keep the logic out of the route

Notice the real decisions — clean the text, reject blanks, build the list HTML — are simple Python. Pulling them into their own functions makes them testable without a running server, exactly like the file-organizer project in Unit 5.

Example
import html

def add_note(notes, text):
    text = text.strip()
    if text:
        notes.append(text)
    return notes

def render_notes(notes):
    if not notes:
        return "<p>No notes yet.</p>"
    items = "".join(f"<li>{html.escape(n)}</li>" for n in notes)
    return f"<ul>{items}</ul>"

notes = []
add_note(notes, "  Buy milk  ")
add_note(notes, "")
print(render_notes(notes))
Output
<ul><li>Buy milk</li></ul>
Pure functions you can test without a server.

Why notes vanish on restart

The list lives in memory, so it’s wiped every time the server restarts. Persisting notes (to a file or database) is the natural next step — but the app works without it, which keeps the project unblocked.

Finish add_note so it ignores blank notes, then confirm the empty-state message shows when nothing valid has been added yet.

def add_note(notes, text):
    text = text.strip()
    # TODO: append text to notes only if it is non-blank
    return notes

def render_notes(notes):
    if not notes:
        return "No notes yet"
    return ", ".join(notes)

notes = []
add_note(notes, "   ")
print(render_notes(notes))

Common mistake: Expecting in-memory notes to survive a restart

Why it happens:

The notes persist while the server runs, so it feels like they’re saved.

How to fix it:

A plain list is wiped on restart. To keep notes, write them to a file or database — that’s the next improvement beyond this project.

Common mistake: Letting blank notes into the list

Why it happens:

Submitting an empty form still calls the add route.

How to fix it:

Strip and check the value before appending, so empty or whitespace-only submissions are ignored.

Common mistake: Putting all the HTML inside route functions

Why it happens:

Returning HTML strings directly is the quickest way to see something.

How to fix it:

Move the markup into templates and keep routes thin. Your views should fetch data and render, not assemble big HTML strings.

Which route shows the list of notes?

Where should the page’s HTML live?

Why do notes disappear after a restart without storage?

Mini exercise (hard)

Build the notes core: add_note(notes, text) appends a stripped, non-blank note and returns the list; render_notes(notes) returns a <ul> of <li> items, or <p>No notes yet.</p> when the list is empty.

Do it here. Finish the code below and press Run to try your answer right in the browser — no setup needed.

def add_note(notes, text):
    # TODO: strip text; append only if non-blank; return notes
    return notes

def render_notes(notes):
    # TODO: return "<p>No notes yet.</p>" when empty,
    #       otherwise a <ul> of <li> items
    return ""

notes = []
add_note(notes, "Buy milk")
add_note(notes, "   ")
add_note(notes, "Walk dog")
print(render_notes(notes))

What to learn next

You assembled the whole unit into a working notes app: a / route that lists notes, an /add route that validates and stores a submission, in-memory data, and a pure add_note()/render_notes() core you can test without a server. You also saw why notes vanish on restart without persistence.

That completes the Intermediate pathobject-oriented Python, practical scripting, and web fundamentals. A great next step is a fuller guided build on the Projects page; the Advanced path (data, APIs, and more) is on the way. When you’re ready, keep building.