Hello! Welcome to your next lesson.
In our last session, we built our first API endpoint, a special URL that returns raw JSON data instead of a full webpage. This was a huge step toward making our application interactive. But as we add more featuresâmore HTML pages, API endpoints, and soon, styling with CSS and interactivity with JavaScriptâour single app.py file and project folder will start to get crowded and disorganized.
Today, we'll address that by learning how to structure our Flask project properly. A well-organized project is easier to build, debug, and expand. We will create dedicated folders for our HTML files (templates) and our CSS, JavaScript, and image files (static), which is the standard and expected way to build Flask applications.
By the end of this lesson, you will be able to structure your project cleanly, separating your Python logic, HTML structure, and static assets.
Why Project Structure Matters
Think of building an application like cooking a meal. You have your ingredients (data), your recipe (Python code), and your serving dishes (HTML/CSS). It would be chaotic to keep them all in one big pile on the counter. Instead, you organize: ingredients in the pantry, recipes in a book, and dishes in the cupboard.
In programming, this idea is called Separation of Concerns. We keep different types of code separate based on their purpose:
- Python (
.py): Handles the application's logic, processes data, and talks to APIs. - HTML (
.html): Defines the structure and content of your web pages. - Static Files (CSS, JS, Images): Control the visual style and interactive behavior of your pages.
Flask is designed with this separation in mind and expects a specific folder structure to work correctly.
The Basic Flask Folder Structure
A standard Flask project has a main folder, and inside it, a Python file for our app and two special subfolders: templates and static.

To understand this structure more clearly, please read the following short text.
This document, from the 'Python Beginners documentation', clearly explains the required folder structure for a Flask app.
Read the section titled 'Folder structure for a Flask app'. Focus on the names of the two key folders (static and templates) and what kind of files belong in each.
As you've just read, the rules are simple but strict:
templatesfolder: This is where Flask automatically looks for HTML files when you use therender_template()function.staticfolder: This is where Flask looks for files that your HTML pages will need, like stylesheets (CSS), browser scripts (JavaScript), and images.
Serving Static Files: CSS, Images, and JavaScript
Placing files in the static folder is the first step. The second is telling our HTML templates how to find them. We can't just write <link href="style.css"> because the browser doesn't know where the static folder is on the server.
Flask provides a special helper function for this called url_for(). When used in a template, url_for('static', filename='...') generates the correct URL path to a file inside your static folder.
This next video provides a great hands-on demonstration of creating the static folder and linking a CSS file and an image from an HTML template.
Flask Tutorial #9 - Static Files (Custom CSS, Images & Javascript)
This tutorial by Tech With Tim will walk you through the practical steps of setting up and using the static folder.
Watch from 01:44 to 10:22. Pay close attention to: The creation of the templates and static folders (01:44). The exact syntax used to link a CSS file: href="{{ url_for('static', filename='style.css') }}" (04:15). How to organize files into subfolders (like static/styles/) and update the filename path accordingly (07:34). How the same url_for function is used for images with an <img> tag (08:25).
Let's Build It
Now, let's put this all together with a simple, structured project.
- Create a new project folder (e.g.,
my_structured_app). - Inside
my_structured_app, create your folder structure:- An
app.pyfile. - A
templatesfolder. - A
staticfolder.
- An
- Inside the
staticfolder, create acssfolder.
Your structure should look like this:
my_structured_app/
âââ app.py
âââ static/
â âââ css/
â âââ main.css
âââ templates/
âââ index.html
Now, add the following code to each file.
app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
# Flask will look for 'index.html' inside the 'templates' folder
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Structured App</title>
<!-- This links to our CSS file in the static/css/ folder -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
</head>
<body>
<h1>Welcome to My Organized Flask App!</h1>
<p>This page is styled by an external CSS file.</p>
</body>
</html>
static/css/main.css
body {
background-color: #f0f8ff; /* A light aliceblue color */
font-family: sans-serif;
text-align: center;
margin-top: 50px;
}
h1 {
color: #4682b4; /* A nice steelblue color */
}
Run your app.py file and visit http://127.0.0.1:5000 in your browser. You should see a page with a blue heading and a light blue background, confirming that your HTML template successfully loaded the CSS file from the static folder!
Test your understanding!
Time to add an image to our project.
- Inside your
staticfolder, create a new folder namedimages. - Find a small image online (or create a simple one) and save it inside the
static/images/folder. Let's assume you named itlogo.png. - Modify your
templates/index.htmlfile to display this image below the<p>tag.
How would you write the <img> tag to correctly display logo.png?
Show answer
You would add the following line inside the <body> of your index.html file, likely after the <p> tag:
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="My App Logo" width="150">
Notice the filename includes the images/ subfolder path. The full index.html would look something like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Structured App</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
</head>
<body>
<h1>Welcome to My Organized Flask App!</h1>
<p>This page is styled by an external CSS file.</p>
<!-- Here is the new image tag -->
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="My App Logo" width="150">
</body>
</html>
A Glimpse at Larger Projects
The structure we learned today is perfect for our project and many small-to-medium Flask applications. As projects become very large, developers sometimes use an even more advanced structure, grouping the app's code into its own sub-directory.

This is just for your awareness. The app.py + static + templates structure is the ideal foundation for us to build upon.
Conclusion
Great job! You've learned the "why" and "how" of organizing a Flask project. This clean structure will make developing your AI writing assistant much more manageable as we add more files and features.
Key Takeaways:
- A good project structure separates logic (Python), structure (HTML), and presentation (CSS, JS, images).
- Flask expects HTML files to be in a folder named
templates. - CSS, JavaScript, and image files belong in a folder named
static. - To link to a static file from an HTML template, you must use the
url_for('static', filename='path/to/your/file')syntax.
In our next lesson, we'll zoom out to understand the big picture of how all these pieces communicate. We'll explore the client-server model, which describes the relationship between the user's browser (the client) and our Flask application (the server). This conceptual understanding will be the perfect setup for our next practical step: making the browser send data to our server without a full page reload.