How to serve static files in Flask
Categories:
Serving Static Files in Flask: A Comprehensive Guide

Learn how to effectively manage and serve static assets like CSS, JavaScript, and images in your Flask applications, from basic setup to advanced configurations.
Flask, a lightweight Python web framework, is excellent for building web applications. A fundamental aspect of any web application is serving static files â resources like CSS stylesheets, JavaScript files, and images that are directly delivered to the client's browser. This guide will walk you through the default Flask static file serving mechanism, how to organize your static assets, and best practices for production environments.
Understanding Flask's Default Static File Handling
By default, Flask is configured to serve static files from a folder named static
located in the same directory as your main application module or package. When you create a Flask application, you can reference these files using the url_for()
function with the special endpoint name 'static'
and a filename
argument.
from flask import Flask, url_for, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
Basic Flask application setup.
To make this work, you'll need a static
folder and a templates
folder in your project root. Here's a typical project structure:
graph TD A[Your Flask Project] A --> B[app.py] A --> C[static/] C --> D[css/] D --> E[style.css] C --> F[js/] F --> G[script.js] C --> H[img/] H --> I[logo.png] A --> J[templates/] J --> K[index.html]
Standard Flask project structure for static files.
Inside your index.html
template, you would link to your static files 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 Flask App</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<h1>Welcome to my Flask App!</h1>
<img src="{{ url_for('static', filename='img/logo.png') }}" alt="App Logo">
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
</body>
</html>
Linking static files in a Jinja2 template.
url_for('static', filename='...')
is crucial. It ensures that your application generates the correct URL for static files, even if your application is deployed under a different path or domain. Avoid hardcoding static file paths.Customizing Static File Paths
While the default static
folder is convenient, you might need to customize its location or even serve static files from multiple directories. Flask allows you to configure the static_folder
and static_url_path
when initializing your Flask
application.
from flask import Flask, url_for, render_template
import os
# Option 1: Custom static folder name
# app = Flask(__name__, static_folder='assets')
# Option 2: Custom static URL path (e.g., /resources instead of /static)
# app = Flask(__name__, static_url_path='/resources')
# Option 3: Both custom folder and URL path
app = Flask(
__name__,
static_folder=os.path.join(os.path.dirname(os.path.abspath(__file__)), 'my_assets'),
static_url_path='/resources'
)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
Customizing static folder and URL path.
If you use static_url_path='/resources'
, your url_for
calls would remain the same, but the generated URLs would look like /resources/css/style.css
instead of /static/css/style.css
. If you change static_folder
to my_assets
, your project structure would adapt accordingly:
graph TD A[Your Flask Project] A --> B[app.py] A --> C[my_assets/] C --> D[css/] D --> E[style.css] A --> F[templates/] F --> G[index.html]
Project structure with a custom static folder name.
static_folder
, ensure the path is correct. Using os.path.join
and os.path.dirname(os.path.abspath(__file__))
helps create robust, platform-independent paths.Serving Static Files in Production
While Flask's built-in static file serving is convenient for development, it's generally not recommended for production environments. Production web servers like Nginx or Apache are highly optimized for serving static content and can do so much more efficiently than a Python application server.
The typical production setup involves configuring your web server to directly serve the static files, bypassing the Flask application entirely. This offloads the task from your Python process, freeing it to handle dynamic requests.
1. Collect Static Files
If you're using a tool like Flask-Assets or a build system (e.g., Webpack), you might have a 'build' or 'dist' directory where all your compiled and minified static assets reside. Ensure these are in a single, accessible location.
2. Configure Web Server
Point your web server (e.g., Nginx) to the directory containing your static files. For example, in Nginx, you would use a location
block to serve files from a specific URL path.
3. Update Flask Configuration
In your Flask application, ensure that url_for('static', ...)
generates URLs that match the path your web server is configured to serve. If your Nginx serves /static/
from /var/www/my_app/static/
, then Flask's url_for
should still generate /static/path/to/file.css
.
Nginx Configuration
server { listen 80; server_name your_domain.com;
location /static/ {
alias /path/to/your/flask_app/static/;
expires 30d;
add_header Cache-Control "public, no-transform";
}
location / {
proxy_pass http://127.0.0.1:8000; # Gunicorn/uWSGI address
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Apache Configuration
<VirtualHost *:80> ServerName your_domain.com
DocumentRoot /path/to/your/flask_app
Alias /static /path/to/your/flask_app/static
<Directory /path/to/your/flask_app/static>
Order allow,deny
Allow from all
</Directory>
<Directory /path/to/your/flask_app>
<IfModule mod_wsgi.c>
WSGIProcessGroup your_app_name
WSGIApplicationGroup %{GLOBAL}
WSGIScriptAlias / /path/to/your/flask_app/wsgi.py
</IfModule>
</Directory>