Skip to main content

Serving Static Files and Resources

When you create a Flask application, it automatically sets up a route to serve static files like CSS, JavaScript, and images from a folder named static located next to your application module. The Scaffold class provides the base logic for resource management, which is inherited by both the Flask application and Blueprint objects.

Configuring the Static Folder

By default, Flask looks for a folder named static relative to the application's root_path. You can customize the folder name and the URL path used to access it during initialization.

from flask import Flask
from pathlib import Path

# Customizing the static folder and URL path
app = Flask(
__name__,
static_folder="assets", # Files located in 'assets/' directory
static_url_path="/public" # Accessed via 'http://domain/public/...'
)

# You can also use pathlib.Path objects
app = Flask(__name__, static_folder=Path("static_files"))

If you use host_matching=True, you must also provide a static_host to the constructor, or Flask will raise an AssertionError during initialization.

Generating Static URLs

To generate a URL for a static file, use the url_for helper with the static endpoint.

from flask import url_for

@app.route("/")
def index():
# Returns '/static/style.css' (or your custom static_url_path)
return url_for("static", filename="style.css")

Serving Static Files Manually

While Flask automatically registers a route for static files, you can manually serve files from the configured static_folder using the send_static_file method. This is useful if you need to perform custom logic before serving the file.

@app.route("/get-manifest")
def manifest():
# Serves 'manifest.json' from the app's static_folder
return app.send_static_file("manifest.json")

The send_static_file method uses send_from_directory internally and respects the SEND_FILE_MAX_AGE_DEFAULT configuration for caching.

Reading Application Resources

If you need to read internal files that are part of your application package (like a SQL schema or a configuration file), use open_resource. This method resolves paths relative to the application's root_path.

# example from flaskr tutorial
with app.open_resource("schema.sql") as f:
db.executescript(f.read().decode("utf8"))

open_resource only supports reading. Valid modes are "r", "rt", and "rb". If you attempt to open a file for writing, it will raise a ValueError.

Managing Instance Resources

For files that need to be written at runtime or should not be part of the version-controlled source code, use the instance folder. The open_instance_resource method allows both reading and writing relative to the instance_path.

# Writing to a file in the instance folder
with app.open_instance_resource("data.log", mode="w") as f:
f.write("Log entry")

# Reading from the instance folder
with app.open_instance_resource("config.json", mode="rb") as f:
config_data = f.read()

Static Files in Blueprints

Blueprints can also serve their own static files. This allows you to package a component with its own assets.

from flask import Blueprint

# Blueprint with its own static folder
admin_bp = Blueprint(
"admin",
__name__,
static_folder="admin_static",
static_url_path="/admin/static"
)

# Accessing blueprint static files in templates:
# {{ url_for('admin.static', filename='admin_style.css') }}

Note that the static route for a blueprint is only registered if static_folder is explicitly provided during the Blueprint creation.

Cache Configuration

You can control how long browsers should cache static files by setting the SEND_FILE_MAX_AGE_DEFAULT configuration option.

from datetime import timedelta

# Set cache timeout to 1 hour
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = timedelta(hours=1)

# Or use an integer (seconds)
app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 3600

If this is set to None (the default), the browser will use conditional requests to check if the file has changed instead of relying on a timed cache.

Troubleshooting

  • Missing Static Route: The static route is only added if has_static_folder is true. For Flask apps, this defaults to 'static', but for Blueprints, it defaults to None.
  • Trailing Slashes: The static_url_path and static_folder setters in the Scaffold class automatically strip trailing slashes to ensure consistent path joining.
  • Root Path Detection: Flask uses the import_name (usually __name__) to find the root_path. If your resources aren't being found, ensure you are passing the correct module or package name to the Flask constructor.
  • Read-Only Resources: open_resource is strictly for reading. If you need to write files, use open_instance_resource or standard Python open() with absolute paths.