Flask Static Files

Static files are CSS stylesheets, JavaScript files, images, and fonts — files that the browser downloads and uses directly without Flask processing them. Flask serves static files automatically from a dedicated folder.

The Static Folder

Flask looks for a folder named static in the same directory as your app.py. Files inside this folder are publicly accessible at the URL path /static/.

Project structure:
myapp/
├── app.py
└── static/
    ├── css/
    │   └── style.css        → /static/css/style.css
    ├── js/
    │   └── main.js          → /static/js/main.js
    └── images/
        └── logo.png         → /static/images/logo.png

Linking Static Files in Templates

Always use url_for('static', filename='...') to reference static files in templates. Hardcoding the path breaks when you move the app to a sub-directory or change the static folder location.

{# CSS link in <head> #}
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">

{# JavaScript before </body> #}
<script src="{{ url_for('static', filename='js/main.js') }}"></script>

{# Image #}
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo">

How url_for Generates Static URLs

url_for('static', filename='css/style.css')
              │
Flask builds: /static/css/style.css
              │
Browser GETs: /static/css/style.css
              │
Flask reads:  myapp/static/css/style.css from disk
              │
Sends:        CSS file bytes to browser

Custom Static URL Path

By default, Flask serves static files at /static. Change this by setting static_url_path when creating the app:

app = Flask(__name__, static_url_path='/assets')

Now files are served at /assets/css/style.css instead of /static/css/style.css.

Custom Static Folder Location

Point Flask to a different folder using static_folder:

app = Flask(__name__, static_folder='public')

Flask now serves files from the public/ folder instead of static/.

Cache Busting with url_for

Browsers cache static files aggressively. When you update style.css, users may still see the old version from their cache. Cache busting forces the browser to fetch the new file by adding a version parameter to the URL.

Set a version in your config:

app.config['STATIC_VERSION'] = '2.1'

Use it in templates:

<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css', v=config['STATIC_VERSION']) }}">

The browser sees a new URL (/static/css/style.css?v=2.1) and fetches the file fresh. Increment the version number every time you deploy CSS or JS changes.

Serving Static Files in Production

The Flask development server serves static files fine during development. In production, a dedicated web server like Nginx handles static files much faster — it reads them directly from disk without calling Python at all.

Development:
  Browser → Flask → reads static/ → sends file

Production:
  Browser → Nginx → reads static/ → sends file  (Python not involved)
          → dynamic requests → Gunicorn → Flask

This setup is faster because Nginx handles hundreds of file requests per second without any Python overhead.

Favicon

The favicon is the small icon browsers show in the tab. Save it as static/favicon.ico and link it in your base template's <head>:

<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">

Summary

Flask automatically serves files from the static/ folder. Use url_for('static', filename='...') in templates to generate correct URLs. Organize static files into subfolders by type (css, js, images). In production, configure Nginx to serve static files directly so Python handles only dynamic requests. Add a version parameter to static file URLs to bust browser caches after updates.

Leave a Comment

Your email address will not be published. Required fields are marked *