whitenoise

Radically simplified static file serving for WSGI and Django apps, with zero external dependencies.

Library
PyPI
v6.12.0
2,762 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
65 /100 Good
Development Activity 72
Maintenance 28
Community 60
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
83 /100 Excellent
Architecture 82
Code Quality 88
Innovation 85
Learning Curve 78

WhiteNoise lets a Python web app serve its own static files directly, without relying on nginx, Amazon S3, or any other external service. Wrap any WSGI application in the WhiteNoise middleware, or drop WhiteNoiseMiddleware into a Django project’s MIDDLEWARE list, and static assets are served with correct gzip/Brotli compression, conditional-GET and byte-range support, and far-future cache headers applied automatically.

It was built for PaaS environments like Heroku where standing up a separate static-file server isn’t practical, but it works equally well in front of a CDN on high-traffic sites, since the CDN absorbs most of the request volume and WhiteNoise only needs to handle origin fetches efficiently. For Django users specifically, a companion storage backend adds hashed, manifest-based filenames so assets can be cached forever without invalidation problems.

What You Get

  • A WSGI middleware that wraps any application and intercepts requests matching known static file paths
  • A Django-specific WhiteNoiseMiddleware that reads WHITENOISE_* settings and integrates with Django’s staticfiles app
  • Automatic gzip and Brotli precompression of eligible files, with correct Accept-Encoding/Vary handling
  • Far-future Cache-Control headers on content that won’t change, plus conditional GET (ETag/Last-Modified) and byte-range support
  • A CompressedManifestStaticFilesStorage backend for Django that produces hashed filenames for safe long-term caching
  • An autorefresh mode for development that re-scans the filesystem on every request instead of caching a static file list

Common Use Cases

  • Serving a Django or Flask app’s static assets from a single-dyno Heroku, Render, or Fly.io deployment with no separate static server
  • Fronting a small-to-medium site with a CDN while keeping static-file logic inside the app instead of managing an S3 bucket or nginx config
  • Local development where autorefresh mode picks up changed static files without a rebuild step
  • Container deployments where adding an nginx sidecar solely to serve static files is more operational overhead than it’s worth

Under The Hood

Architecture

The core (src/whitenoise/base.py) is a plain WSGI middleware class that wraps an application callable, builds an in-memory files dict (or, in autorefresh/dev mode, a list of watched directories) mapping URL paths to StaticFile objects computed once at startup via add_files/update_files_dictionary, and answers matching requests itself in __call__ before ever touching the wrapped app. Response generation is delegated to responders.py, where StaticFile, Redirect, and related classes model byte-range, conditional-GET, and gzip/Brotli-variant negotiation as small self-contained objects, with media_types.py centralizing content-type lookup. Django integration (middleware.py, storage.py) is a thin subclass — WhiteNoiseMiddleware inherits directly from WhiteNoise and maps settings.WHITENOISE_* onto the same constructor kwargs, while CompressedManifestStaticFilesStorage plugs into Django’s staticfiles app for hashed filenames — so the whole system is one core abstraction with two integration adapters layered on top.

Tech Stack

Pure Python, requires-python >=3.10, with zero mandatory runtime dependencies (brotli is an optional extra). Built with uv_build as the PEP 517 backend and locked via uv.lock; ruff handles linting (isort, pyupgrade, flake8-bugbear/simplify rule sets) wired in through pre-commit; docs are Sphinx + furo, built via Read the Docs; CI (GitHub Actions) runs the pytest suite across the supported Python/Django matrix. Optional integration points are Django’s staticfiles framework via a custom Storage backend and Middleware subclass, or any generic WSGI application directly.

Code Quality

tests/ is a full parallel suite (test_whitenoise.py, test_responders.py, test_compress.py, test_storage.py, test_django_whitenoise.py, test_media_types.py, test_string_utils.py, test_runserver_nostatic.py) run with pytest and pytest-randomly, with branch coverage tracked via coverage.py and reported at a high percentage on the project’s own badge. The codebase uses from __future__ import annotations throughout plus real type hints on public constructors and callables; errors are explicit exception classes (MissingFileError, IsDirectoryError) rather than silently swallowed; ruff plus pre-commit enforce style, and CI runs the matrix on every push. No stray debug output or bare excepts turned up in the core modules.

API Design Adoption is a one- or two-line change — wrap a WSGI app in WhiteNoise(app, root=...) or add WhiteNoiseMiddleware to Django’s MIDDLEWARE — and nearly every option (autorefresh, max_age, allow_all_origins, index_file, immutable_file_test, add_headers_function) has a sensible default, so zero-config usage already does the right thing. Django users get additional auto-configuration, with WHITENOISE_* settings falling back to Django’s own DEBUG/STATIC_URL, so there’s effectively no boilerplate between installed and working. The tradeoff is a deliberately small public surface — a handful of constructor kwargs and one Storage class — with behavior documented on Read the Docs rather than fully discoverable from the API alone.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers