CS50 Week 9 Explained: Building Web Apps with Flask
Week 9 brings the whole course together. Python (Week 6) runs on a server, SQL (Week 7) stores the data, and HTML, CSS and JavaScript (Week 8) show it to the user. The glue is Flask, a small Python framework for web applications. By the end of the week you'll have built one that remembers who's logged in.

Jump to the key moments
- 0:43Flask
- 28:41Forms
- 33:31Jinja
- 37:12Templates
- 48:10Request methods
- 54:22Frosh IMs
- 1:31:10SQLite and Python
- 1:57:05Cookies and sessions
- 2:02:47Shopping cart
- 2:20:29APIs
Static pages vs web applications
In Week 8, every visitor got the same files. A web application generates each page when it's requested, based on who's asking, what they typed and what's in the database. Flask handles the parts that stay the same (receiving requests, routing them to your code, sending responses), so you only write the parts specific to your app.
Routes and templates
A Flask app is mostly routes: a decorator like @app.route("/greet") above a function that returns the page for that URL. Pages are templates, HTML files in a templates folder that use Jinja syntax: {{ name }} to insert a value, and {% for %} or {% if %} for logic. A shared layout.html holds the common frame, and every other template extends it. It's the same don't-repeat-yourself lesson from Week 1, applied to HTML.
GET, POST and forms
A form can send data in two ways. GET puts it in the URL (?name=Ammar), which is fine for searches you might bookmark. POST sends it in the body of the request, which is right for anything private or anything that changes data. Flask reads GET values from request.args and POST values from request.form. One route can handle both methods and behave differently for each.
Frosh IMs: validation and the database
The lecture's main example is a sign-up site for student sports. It shows why you must validate on the server: anyone can edit the HTML in their browser and submit values your form never offered. It then saves registrations to SQLite with CS50's SQL library and ? placeholders, because the SQL injection warning from Week 7 still applies.
Cookies and sessions
HTTP has no memory of its own: each request arrives on its own. Cookies fix this. The server gives the browser a small token, and the browser sends it back with every request. Flask's session uses that token to remember things per user, like who's logged in or what's in their shopping cart.
APIs and JSON
A route doesn't have to return HTML. It can return JSON, structured data that JavaScript can fetch and display without reloading the page. That's the pattern behind search-as-you-type, and it's how services talk to one another: an API is just URLs that return data instead of pages.
Problem Set 9: what it asks
- Birthdays: a one-page Flask app that lists friends' birthdays from a database and adds new ones through a form.
- C$50 Finance: a full app where users register, log in, look up real stock prices and "buy" and "sell" shares with play money, with a portfolio and a transaction history. It's the biggest problem in the course.
Where people get stuck
- Finance: build it in the order the spec gives. Register first, because you can't test anything else without a user. Then quote, buy, index, sell and history.
- Design the database before coding buy. Most people add a transactions table (who, which stock, how many shares, what price, when), and everything else is a query over it. Sketch the columns on paper.
- Trust nothing from the form. Negative share counts, text where a number should be, a stock symbol that doesn't exist: check each one on the server and return a clear error.
- "Internal Server Error": the real error is in the terminal where
flask runis running, not in the browser.
Check yourself
When should a form use POST instead of GET?
When the data is private, like a password, or when submitting it changes something, like buying shares. GET puts the values in the URL and in the browser's history.
Why isn't client-side validation enough?
Users control their own browser. They can edit the HTML or send requests directly, so the server has to check everything.
How does a site remember that you're logged in if HTTP is stateless?
With a cookie. The browser sends a session token with every request, and the server uses it to look up your session.
What's the difference between a route that returns HTML and an API route?
An API route returns data, usually JSON, for code to use. An HTML route returns a page for people to read.
APIs are how AI agents use tools. Learn how that works, including MCP, in the API Lab.
Try the API Lab →