Host-based URL routing and host-aware reversing for Django, with zero call-site changes.
These guides are task-focused. For the exhaustive settings and system check tables, see the settings reference; for the explicit API and testing helpers, see the API reference.
The two-line install
INSTALLED_APPS = [
# ...
"hostmap",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"hostmap.middleware.HostmapMiddleware", # before CommonMiddleware
"django.middleware.common.CommonMiddleware",
# ...
]
Then declare one host map:
HOSTMAP = {
"www": {"subdomain": "www", "urlconf": "config.urls.www"},
"api": {"subdomain": "api", "urlconf": "config.urls.api"},
"apex": {"host": "example.com", "redirect_to": "www"},
}
HOSTMAP_PARENT_DOMAIN = "example.com"
HOSTMAP_DEFAULT = "www"
ROOT_URLCONF still points at your default host's URLconf, exactly as Django
requires.
The promise
With www active, nothing at the call site changes:
| Call | Returns |
|---|---|
reverse("blog:index") |
/blog/ (byte-identical to stock Django) |
reverse("api:user-detail", args=[7]) |
https://api.example.com/users/7/ |
{% url "api:user-detail" 7 %} |
the absolute URL, no template changes |
Same-host links stay relative. Cross-host links come back absolute. The
stock reverse(), reverse_lazy() and {% url %} do this everywhere,
including inside third-party apps you never touch, because hostmap hooks
resolver acquisition rather than patching reverse itself. See
how host-aware reversing works
for why that distinction matters.
I want to...
| I want to... | Go to |
|---|---|
| Build a two-host project from scratch | Multi-host in ten minutes |
| Route a subdomain to its own URLconf | Route a subdomain to its own URLconf |
Understand {% url %} and reverse() behaviour |
Link across hosts in templates and Python |
| Reverse a URL from a Celery task, email, or webhook | Reverse out of a request |
Redirect the apex domain to www |
Add a redirect host |
| Route arbitrary subdomains (multi-tenant style) | Use wildcard subdomains |
| Move off django-hosts | Migrate from django-hosts |
| Write tests that hit the right host | Test host routing |
| Deploy behind nginx or another reverse proxy | Run behind a proxy |
| Disable the reverse patch and keep routing only | Turn off reversing |
| Understand the resolver-acquisition seam | How host-aware reversing works |
| Understand cross-host resolution order | Resolution order |
Look up a HOSTMAP_* setting |
Settings reference |
Look up hostmap.urls or hostmap.testing |
API reference |
| Fix an error or unexpected behaviour | Troubleshooting |
How these docs are organised
The documentation follows the Diátaxis model:
- Tutorial: a single, opinionated path from nothing to a working two-host project. Start here if you are new.
- How-to guides: recipes for specific tasks. Each one states a goal, lists prerequisites, gives runnable steps, and shows how to verify the result.
- Explanation: the "why": the resolver-acquisition seam, why same-host reversing is free, and the fixed cross-host resolution order. Read these to build a mental model.
- Settings reference and API reference: the exhaustive lookup tables.
- Troubleshooting: symptom, cause, fix.
New to django-hostmap?
- Follow the tutorial end to end.
- Read
how host-aware reversing works
to understand why the package can fix third-party apps'
reverse()calls without changing them. - Keep the settings reference and troubleshooting page open as you integrate, and read run behind a proxy before you deploy: a misrouted Host header is the most common support issue.