Best practices¶
Practical defaults for production Hedron apps from the 0.8 compatibility baseline onward.
A production-minded baseline¶
Keep the application constructor, page shell, and replaceable views explicit. Read secrets from the environment and let authenticated responses select a private cache policy:
import os
from fastapi import Request
from hedron import Hedron, InteractionResult, Stack, Text
app = Hedron(
title="Account console",
security="standard",
explorer="off",
session_secret=os.environ["HEDRON_SESSION_SECRET"],
)
@app.view("/account/status")
def account_status(request: Request) -> InteractionResult:
signed_in = bool(request.session.get("user_id"))
return InteractionResult(
content=Text("Signed in" if signed_in else "Signed out"),
cache="private" if signed_in else "vary-htmx",
)
@app.page("/")
def home():
return Stack(
Text("Account console"),
account_status(),
account_status.refresh_button("Refresh status"),
)
This keeps one application authority: the session remains server-owned, the view owns its cache decision, and the page composes the resulting handle without hand-writing HTMX attributes.
Pages vs fragments¶
- Use
@app.page(or fullPage) for document shells and first paint. - Use
@app.viewroutes for replaceable views and@app.actionfor HTMX mutations into declared regions. - Declare
FragmentRegionallowlists when OOB or retarget is in play—do not authorize one#idand emithx-swap-oobfor another.
CSRF and secrets¶
- Issue CSRF on safe GETs; send
X-CSRF-Token(or form field) on unsafe methods. - Flask: enforced on
hedron_route/HedronFlask.respond. - Django: use middleware; align
CSRF_HEADER_NAMEfor portable headers. - Never commit real
session_secret/SECRET_KEYvalues; rotate per environment.
URLs and redirects¶
- Pass navigation/asset URLs through
SafeUrl.parse(..., purpose=...). - Prefer
redirect_local/ interaction redirects; avoid open redirects via raw headers. - Adapter
extra_headerscannot overwrite validatedHX-*URL/selector fields or weakenCache-Controltopublic.
Caching¶
- Prefer
cache="private"orno-storefor authenticated fragments. - Use
vary-htmxwhen responses differ byHX-Request/ target. - Include tenant or user in cache keys when responses are tenant-scoped.
Templates¶
- Prefer Python components for reusable behavior and authorization. Install
hedron-jinjawhen trusted authors need standards-first control over HTML, CSS, JavaScript, Jinja, and HTMX; bind every callable component alias explicitly and keep dynamic trust crossings visible. HDN is not available on the 0.9+ train. - Do not put secrets or untrusted HTML in templates—use
TrustedHtmlat trust boundaries.
Adapters¶
- Install
hedron-flask/hedron-djangoseparately; they never pull FastAPI. - Prefer
hedron_django.formsandDjangoQuerySetDataSourceover ad-hoc bridges. Capture UI (CameraCapture, …) is Supported on the current train — see What's ready. - For mutations on Flask/Django: CSRF + forms bridge (or host forms) and polling for job status.
Testing¶
- Unit-render with
render(...)for components. - Use TestClient / Flask/Django clients for CSRF and fragment headers.
- Opt into browser suite (
HEDRON_BROWSER=1) for critical HTMX flows.
Anti-patterns¶
| Avoid | Prefer |
|---|---|
| Full-page HTMX swaps for every click | Declared FragmentRegion updates |
Cache-Control: public on authenticated HTML |
private / no-store / vary-htmx |
Explorer (development) in production |
explorer="off" or secured with real auth |
Unbounded Auto on huge objects |
Bound depth / explicit tables |
Raw HX-* headers that bypass validated fields |
InteractionResult fields |
| Assuming SSE/WS survive every proxy | Polling fallback + proxy buffering off |
| One in-memory job backend across workers | Sticky sessions or shared JobBackend |
See also Security, HTMX interactions, Deployment, Enterprise diligence.
Day-one defaults¶
- Prefer the canonical
@app.page/@app.view/@app.actionroles over hand-wired lower-level routes unless you need fullPagecontrol. - Require
hedron>=1.0.0(and matching host packages) in every environment. - Keep Explorer off and
session_secretfrom the environment in production. - Declare HTMX regions; undeclared targets fail closed — treat 403s as configuration bugs.
- Prefer polling for job UIs until you have proxy/load evidence for SSE/WebSocket.
See also Ship, Security, and What’s ready.