go-htmx: server side helpers for HTMX headers in Go
Seamless HTMX integration in golang applications
At a glance
- What is it?
- go-htmx is a small Go package that gives a server side view of what HTMX is doing: whether a request came from HTMX, whether it was boosted, and how to set the swap, trigger and notification response headers. It does not replace your templates or your router, and it is explicitly shaped by the use cases its author met in real projects.
- Who is it for?
- Adopt go-htmx when you serve HTMX from a Go application and want the response headers and request checks in one place instead of scattering string literals across handlers, and when your templates will keep returning the same components for full and partial renders.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 21 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A header helper package, not a framework
go-htmx is a Go package for working with HTMX from the server side. The README describes it as a set of tools to manage swap behaviours, trigger configurations and other HTMX related functionality in a Go server environment, aimed at enhancing server side handling of HTML generated with the HTMX library.
That framing sets the scope precisely. The package does not render templates, does not route requests and does not ship a client side script. It deals with the part of HTMX that lives on the server: reading the request headers HTMX sends, and writing the response headers HTMX understands.
The features list is short and each item is a discrete unit of work. Component Rendering means you can respond to an HTMX request with a partial component rather than a whole page. Swap Configuration covers the style, timing and scrolling options of the `HX-Swap` header. Trigger Management handles the `HX-Trigger` header, for both simple events and detailed ones with a payload. Middleware Support integrates with Go middleware for header configuration. And the handler implements the io.Writer interface, so you write output the way you normally would.
The most important line in the README is the disclaimer. The package is built around the specific need to work with HTMX in a Go environment, and all the functionality has a certain use case in various projects the author has worked on. This is a personal utility library with a public API, not a product with a design committee, and reading it that way tells you where to look when something does not do what you expected.
Four request checks and the partial render rule
The handler classifies the incoming request, and the classification is where most of the practical value sits.
`IsHxRequest` checks whether the incoming HTTP request was made by HTMX at all, which lets you return a partial HTML snippet instead of a full page. `IsHxBoosted` determines whether the request is boosted, the enhancement where a normal link or form is upgraded to an AJAX style request. `IsHxHistoryRestoreRequest` covers the case where the browser is restoring content from its own history.
The fourth check is the interesting one. `RenderPartial` returns true for HTMX requests that are either standard or boosted, as long as they are not history restore requests. The README frames it as a combined check used to decide whether a partial render is appropriate.
That definition carries a design decision. History restore requests are excluded on purpose, because when the browser restores a page from history it is asking for the page as it was, not for a fragment to be swapped in. A handler that used a naive IsHxRequest check would return a partial for a history restore and the user would see a broken page.
The signatures are plain and stable:
func (h *Handler) IsHxRequest() boolfunc (h *Handler) RenderPartial() boolSo the typical handler reads as a sequence of questions about the request, followed by a response. The README's own guidance is to use RenderPartial as the signal for returning only the HTML fragments needed to update part of the page instead of rendering the entire page.
Swaps and triggers as builder objects
Response headers are set through small builder objects, which is the part of the API with the most obvious shape.
A swap is described as a way to replace the content of a dom element with the content of the response, done by setting the `HX-Swap` header to the id of the element you want to swap. The package expresses that as a value you construct and then hand to the handler:
func (c *Controller) Route(w http.ResponseWriter, r *http.Request) {
// initiate a new htmx handler
h := a.htmx.NewHandler(w, r)
// Example usage of Swap
swap := htmx.NewSwap().Swap(time.Second * 2).ScrollBottom()
h.ReSwapWithObject(swap)
_, _ = h.Write([]byte("your content"))
}The chain style reads well: a swap value carries the delay and the scroll behaviour, and `ReSwapWithObject` applies it to the response. Triggers work the same way, with `NewTrigger` and methods to add an event or to add an event with a detail payload.
The trigger header is what lets the server push events back to the browser. The README notes that trigger events are a way to trigger events on the dom element, done by setting the `HX-Trigger` header to the event you want to trigger.
The package offers several ways to apply a trigger, and the choice is about timing. `TriggerWithObject` sends the trigger with the response, `TriggerAfterSwapWithObject` fires it once the swap has happened, and `TriggerAfterSettleWithObject` fires it after settling. That distinction matters in practice: an event fired too early lands in a page that has not finished swapping and gets lost, so having the three variants available is not decoration.
The handler also carries plain header helpers for the rest of the HTMX protocol, such as `PushURL` and `ReTarget`, so a route can set a URL to push into history and retarget a response at a specific element without writing header strings by hand.
Wiring it into a Go server
Installation is a single module fetch:
go get -u github.com/donseba/go-htmxThe module itself declares Go 1.22 as its language version:
module github.com/donseba/go-htmx
go 1.22The usage pattern in the README is deliberately small. An application holds one HTMX instance, creates a handler per request from it, asks the handler questions about the request, sets the response headers it needs, and writes the body as usual.
package main
import (
"log"
"net/http"
"github.com/donseba/go-htmx"
)
type App struct {
htmx *htmx.HTMX
}
func main() {
// new app with htmx instance
app := &App{
htmx: htmx.New(),
}
mux := http.NewServeMux()
// wrap the htmx example middleware around the http handler
mux.HandleFunc("/", app.Home)
err := http.ListenAndServe(":3000", mux)
log.Fatal(err)
}The `htmx.New()` instance is stored on the application struct, and `NewHandler(w, r)` is called inside each route handler. That split matters for the middleware story: the README lists Middleware Support as a feature, and the comment in the example about wrapping the example middleware around the http handler points at the intended place to inject common header behaviour, rather than repeating it in every route.
Because the handler implements io.Writer, the last line of a route is an ordinary write, and the README tells you to check the browser inspector to confirm the headers were set. That is a useful habit to keep during development, since a missing response header shows up as a page that does not swap rather than as an error.
Where the package stops and your code starts
The limitations here are not bugs, they are the shape of the package.
First, there is no client side. The repository does not include the HTMX library itself or any JavaScript, so you still have to load htmx in your pages and attach it to elements. This is a server side helper library and nothing more.
Second, there is no rendering layer. The feature list mentions component rendering, but what the package gives you is the ability to decide whether to send a partial, not a way to render one. The templates stay wherever they already live, and if your application uses a template engine, the two responses still have to be written by you.
Third, the API surface is the author's use cases, and the disclaimer says so plainly. There is a COMPONENTS.md file at the top of the repository alongside DESIGN_DECISIONS.md and LOB.md, the last documenting the locality of behaviour, which suggests the package is deliberately split so that each piece behaves predictably where it is used. That is good design discipline, but it also means an operation you expected to find may simply not exist, and the documentation you need is split across several markdown files rather than one page.
There is one more practical consideration. The example uses the standard library router with a single route, and the notification handling section of the README is cut off mid sentence, so the exact list of notification helpers is not visible in the documentation at hand. If notifications are the reason you are considering the package, check the package documentation on pkg.go.dev for the current list before you plan around it.
Server side rendering versus a JavaScript client
There is a real alternative for the same problem, and the difference is where the complexity lives.
The HTMX approach keeps the interaction on the server. A click produces an HTTP request, the server decides what to send, and the browser swaps it in. The Go package here serves that model by making the request classification and the response headers explicit and typed.
The alternative is a client side framework that owns the state and talks to JSON endpoints. The difference in approach is concrete: in the server rendered model, the HTML fragment is the API, so a route that returns HTML for a browser and the same fragment for an HTMX request shares one code path through RenderPartial. In the client rendered model, the API returns data, the state lives in the browser, and the server never learns whether the user is on a fast connection or a slow one.
The trade is not free either way. Server rendered fragments mean your server handles more requests and your templates have to produce partial views. Client side rendering moves work to the browser and turns every endpoint into a data contract. For a Go team that already writes HTML templates and prefers one language, the server side model is usually the smaller change, and a package like this one removes the part of it that is fiddly, namely the headers.
If you already run HTMX in another stack, the logic translates directly. The headers are the same, the request checks are the same, and what changes is only the syntax of the language they are written in.
Licence, cadence and the example programs
go-htmx is released under the MIT licence, with the licence file at the top of the repository and the badge in the README pointing at it. MIT permits commercial use, modification and redistribution provided the copyright notice and licence text are retained.
The release history shows a steady line: v1.13 on 2026-03-29, v1.13.1 on 2026-04-07 and v1.13.2 on 2026-10-03. The repository is not archived and the last push was on 2026-10-03, the same day as the most recent tag, so the published version matches the state of the tree. The minor version has moved through a lot of numbers for a small library, which is normal for a package without a large public API surface to stabilise.
The repository also ships example programs, and the directory names describe the range of use cases the author had in mind: examples/embedfs/ for embedding a file system, examples/pokedex/, examples/render/, examples/snake/, examples/sse/ and examples/tiktaktoe/. The sse directory is worth noting, since server sent events are the natural companion to HTMX for pushing updates rather than polling for them, and the presence of a dedicated example suggests the author works on that side too.
For a package this small, adoption risk is mostly about the single maintainer. The MIT licence and the MIT-licensed client library it complements mean there is no licensing obstacle, and the Go module path is stable, but there is one person behind the design decisions, the tests and the documentation.
Editorial conclusion
Adopt go-htmx when you serve HTMX from a Go application and want the response headers and request checks in one place instead of scattering string literals across handlers, and when your templates will keep returning the same components for full and partial renders. Do not adopt it as a template engine, a router, or a way to bring HTMX to a codebase that does not already use it, because the package only manipulates headers and request classification, and the README states the functionality comes from specific use cases rather than a general design. Before integrating, read DESIGN_DECISIONS.md and LOB.md, since the author documents the reasoning and the locality of behaviour there, and decide which response headers you will set per route rather than accepting the defaults.
Frequently asked questions
How do I install go-htmx?
Run `go get -u github.com/donseba/go-htmx`. The module declares Go 1.22 as its language version and has no other dependencies listed in go.mod.
How do I detect that a request came from HTMX in Go?
Call `IsHxRequest()` on the handler created with `NewHandler(w, r)`. The package also offers `IsHxBoosted()`, `IsHxHistoryRestoreRequest()` and `RenderPartial()`, which returns true for standard or boosted HTMX requests that are not history restores.
How do I set the HTMX swap header in go-htmx?
Build a swap value with `htmx.NewSwap()`, chain the options such as a delay and `ScrollBottom()`, and pass it to the handler with `ReSwapWithObject(swap)`. The README describes swapping as setting the `HX-Swap` header to the id of the dom element to replace.
What is the difference between the trigger methods in go-htmx?
All three send an `HX-Trigger` header built from a trigger object, but they differ in timing. `TriggerWithObject` sends it with the response, `TriggerAfterSwapWithObject` fires it after the swap, and `TriggerAfterSettleWithObject` fires it after settling.
Does go-htmx include the htmx JavaScript library?
No. The repository is a Go package for server side handling of HTMX requests and headers, and it does not ship the client side library or a template engine, so you still load htmx in your pages and render the HTML fragments yourself.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/donseba-go-htmx)Was this useful?