Flask
Web Development
Python
Static Files
Server Configuration

How to serve static files in Flask

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Flask can serve static files out of the box, and for most projects the default setup is enough. If you put files under a static directory and reference them with url_for('static', filename=...), Flask will generate the correct URLs for CSS, JavaScript, and images.

The bigger question is not how to make it work, but when to rely on Flask directly and when to let a front-end web server or CDN handle static assets in production.

The Default static Folder

A basic Flask application automatically exposes a static folder located next to your app module.

python
1from flask import Flask, render_template
2
3app = Flask(__name__)
4
5@app.route("/")
6def index():
7    return render_template("index.html")
8
9if __name__ == "__main__":
10    app.run(debug=True)

With a layout like this:

text
1project/
2  app.py
3  static/
4    css/style.css
5    js/app.js
6    images/logo.png
7  templates/
8    index.html

Flask serves those files automatically under /static/....

Reference Static Files in Templates

In templates, do not hardcode /static/... manually if you can avoid it. Use url_for so the URL is generated correctly.

html
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo">

This is the standard Flask pattern. It keeps your templates portable if the app's root path or static URL path changes later.

Customize the Static Folder or URL Path

If you want to store static assets somewhere else, you can configure that when creating the app.

python
1from flask import Flask
2
3app = Flask(
4    __name__,
5    static_folder="assets",
6    static_url_path="/public"
7)

Now files in assets are served under /public/... instead of /static/....

That is useful when integrating with an existing project structure or when you want a cleaner public URL.

Serve Files from Another Directory

Sometimes you need a custom route that serves files from a directory not registered as the app's main static folder. Use send_from_directory for that.

python
1from flask import Flask, send_from_directory
2
3app = Flask(__name__)
4
5@app.route("/downloads/<path:filename>")
6def downloads(filename):
7    return send_from_directory("download_files", filename)

This is a good fit for downloadable assets or controlled file serving. It is better than reading the file yourself and constructing the response manually.

Development Versus Production

Flask's built-in static serving is fine in development and perfectly acceptable for many small deployments. In higher-traffic production systems, it is common to let Nginx, Apache, or a CDN serve the static assets instead.

Why? Static file servers are better at efficient caching, compression, connection handling, and offloading work from the Python application process.

A common pattern is:

  • Flask handles dynamic routes and API responses
  • Nginx serves /static/...
  • long-lived cache headers are applied to versioned assets

The Flask code does not need to change much. The deployment architecture changes instead.

Add Cache-Friendly File References

If static assets change over time, browsers may cache them aggressively. A simple approach is to version the filename, such as app.v2.js, or use a build pipeline that generates hashed filenames.

Even when Flask is serving the files, cache-friendly asset naming reduces stale browser behavior and improves performance.

Common Pitfalls

  • Hardcoding /static/... in templates instead of using url_for('static', ...).
  • Putting files in the wrong directory and expecting Flask to find them automatically.
  • Using send_from_directory for everything when the normal static folder would be simpler.
  • Assuming Flask's built-in server is the best way to serve static assets in a high-traffic production setup.
  • Ignoring browser caching behavior and then wondering why old CSS or JavaScript appears to "stick."

Summary

  • Flask serves files from a static folder automatically.
  • Use url_for('static', filename=...) in templates to generate correct asset URLs.
  • Customize static_folder and static_url_path when your project structure requires it.
  • Use send_from_directory for special-purpose file-serving routes.
  • For serious production traffic, it is often better to let Nginx or a CDN serve static assets.

Course illustration
Course illustration

All Rights Reserved.