Implementing a Simple Static File Server in a Lightweight Python Web Framework
Serving static files—like CSS, JavaScript, images, or fonts—is a basic requirement for any web application. Even in a minimal Python framework, you can add support for static file delivery with only a few lines of code.
Why Serve Static Files
Static assets are essential for rendering pages and enhancing UX. Without them, even the most functional web app will look and feel incomplete.
You may use a reverse proxy (like Nginx) in production, but during development or for embedded apps, your framework should handle static file serving directly.
Basic Strategy
To serve static files:
- Match requests with a
/static/
prefix - Map the request path to a file in a designated directory
- Read the file’s contents
- Return the appropriate content type in the response
Directory Structure
A simple folder layout:
myapp/
static/
style.css
logo.png
app.py
When a request comes in for /static/style.css
, your server should look for static/style.css
on disk.
Static File Handler
Here’s a minimal static file responder:
import os
import mimetypes
def serve_static(request):
path = request.get("path", "")
if not path.startswith("/static/"):
return None # Not a static file
file_path = path.lstrip("/")
full_path = os.path.join(os.getcwd(), file_path)
if not os.path.exists(full_path) or not os.path.isfile(full_path):
return "404 Not Found"
with open(full_path, "rb") as f:
content = f.read()
mime_type, _ = mimetypes.guess_type(full_path)
return {
"status": 200,
"headers": {"Content-Type": mime_type or "application/octet-stream"},
"body": content
}
Integrating with Your Framework
In your main request handler, check for static files before routing:
def handle_request(path, request):
static_response = serve_static(request)
if static_response:
return static_response
# ...fallback to routing
return router.dispatch(path, request)
Serving HTML Too
You can extend this to serve .html
files as static pages (e.g. from a public/
directory), useful for SPA apps or error pages:
if path.endswith(".html"):
mime_type = "text/html"
Content-Type Detection
Python’s mimetypes
module can guess common file types like:
-
.css
→ text/css -
.js
→ application/javascript -
.png
→ image/png -
.woff2
→ font/woff2
Fallback to application/octet-stream
if unknown.
Development vs Production
This static file server works well during development. In production:
- Use a proper web server (e.g. Nginx, Apache) for better performance
- Enable caching and compression
- Serve from a CDN when possible
Optional Features
Add these if needed:
- Caching headers
- Range requests for media
- Directory listing (useful during dev)
- SPA fallback (e.g., always return
index.html
)
Wrap-Up
Serving static files doesn’t require a full-featured web server. With a few simple checks and filesystem access, your lightweight Python framework can deliver assets effectively during development or even in embedded scenarios.
Want to dive deeper? Check out my 20-page PDF guide: Building a Lightweight Python Web Framework from Scratch