A Traefik middleware plugin that copies values from incoming HTTP request query parameters into HTTP request headers before the request reaches the next handler in the chain.
It is useful when an upstream service expects authentication tokens, tenant IDs, or other metadata in headers, but clients (or legacy integrations) only have the ability to send them as query parameters.
For every configured mapping, the plugin:
overwrite: true is set.values[0] is used).bearer: true, the value is prefixed with Bearer before being set — useful for turning
a query parameter directly into an Authorization header.remove: true, deletes the query parameter from the request URL so it is not forwarded
upstream.The plugin never touches the response — it only rewrites the request before calling the next handler.
Traefik plugins are not compiled into a binary you install separately — Traefik downloads the plugin source and runs it through its embedded Yaegi interpreter. You only need to reference it in Traefik's static configuration.
Pin a specific tagged version (recommended for production):
experimental:plugins:query-to-header:moduleName: github.com/muench-dev/query-to-headerversion: v0.1.0
# traefik.toml[experimental.plugins.query-to-header]moduleName = "github.com/muench-dev/query-to-header"version = "v0.1.0"
# CLI--experimental.plugins.query-to-header.modulename=github.com/muench-dev/query-to-header--experimental.plugins.query-to-header.version=v0.1.0
Point Traefik at a local checkout instead of a tagged release by using
localPlugins and mounting/copying this repository into Traefik's plugins
directory (./plugins-local/src/github.com/muench-dev/query-to-header by default):
experimental:localPlugins:query-to-header:moduleName: github.com/muench-dev/query-to-header
Once declared in the static configuration, configure it as a middleware and attach it to a router:
http:middlewares:my-query-to-header:plugin:query-to-header:mappings:- query: tokenheader: X-Tokenremove: trueoverwrite: falserouters:my-router:rule: Host(`example.com`)service: my-servicemiddlewares:- my-query-to-header
Equivalent labels (Docker provider):
labels:- "traefik.http.middlewares.my-query-to-header.plugin.query-to-header.mappings[0].query=token"- "traefik.http.middlewares.my-query-to-header.plugin.query-to-header.mappings[0].header=X-Token"- "traefik.http.middlewares.my-query-to-header.plugin.query-to-header.mappings[0].remove=true"
| Option | Type | Description | Default |
|---|---|---|---|
query | string | Name of the query parameter to read. Required. | - |
header | string | Name of the HTTP header to set with the query parameter's value. Required. | - |
remove | bool | Remove the query parameter from the request URL after copying it. | false |
overwrite | bool | Replace an existing header with the same name instead of leaving it untouched. | false |
bearer | bool | Prefix the header value with Bearer (e.g. for Authorization headers). | false |
Multiple mappings can be declared; an empty query or header on any mapping causes the
middleware to fail to load (validated in New, at construction time, not per-request).
| File | Purpose |
|---|---|
query_to_header.go | Plugin implementation: Config, CreateConfig, New, ServeHTTP. |
query_to_header_test.go | Unit tests using httptest. |
.traefik.yml | Plugin manifest required by the Traefik Plugin Catalog. |
go.mod | No third-party dependencies — required for Yaegi compatibility. |
.golangci.yml | Lint configuration. |
justfile | lint, test, vendor, clean recipes (run with just). |
.release-it.json | Config for release-it (must be installed globally). |
go build ./... # compile-correctness check (plugin is never shipped as a binary)go vet ./...go test -v -cover ./... # run all testsgo test -run TestName -v ./... # run a single testgolangci-lint run # lint, config in .golangci.ymljust # default recipe: lists all available recipes
./plugins-local/src/github.com/muench-dev/query-to-header
relative to your Traefik working directory.localPlugins static configuration shown above.Releases are tag-driven. release-it (install it
globally, e.g. brew install release-it or npm install -g release-it) is used locally to
bump the version, commit, create the vX.Y.Z tag, and push it:
release-it # interactively pick the version bumprelease-it patch # or specify the bump directly
release-it only creates and pushes the git tag — it does not publish to npm or create a
GitHub Release itself (see .release-it.json). Pushing the tag triggers the release GitHub
Actions workflow, which runs goreleaser to publish the actual GitHub Release.
Traefik plugins run inside Yaegi, which only reliably supports the Go standard library.
Do not add third-party dependencies to go.mod — the plugin must remain dependency-free to
load correctly in the Traefik Plugin Catalog and in Yaegi generally.