Build features
Versions marked “overview” do not contain this page. Selecting one opens that version’s documentation overview.
On this page
Praxis is composed at build time with Cargo features. Several subsystems are optional so you can build a proxy that carries only what a deployment needs: a smaller binary, a leaner dependency tree, or no external observability and admin surface at all.
Most features are on by default. Build the standard binary with:
cargo build -p praxis-proxy --release
which includes hot-reload, the admin surface, and the policy filter.
Build the leanest possible binary (every optional subsystem off) with:
cargo build -p praxis-proxy --release --no-default-features
and add back individual features as needed:
cargo build -p praxis-proxy --release --no-default-features --features admin-api
For a policy-free build that keeps everything else, name the features you want instead:
cargo build -p praxis-proxy --release --no-default-features \
--features config-reload,admin-api
For that exact invocation the guarantee holds: every Praxis crate depends on
praxis-proxy-filter without dependency defaults, so dropping the server’s
policy-engine feature leaves the filter’s policy-engine off and the policy
engine’s dependency tree out of the build. make release-fips is this build
with the feature list kept in one place; see FIPS 140-3 for what
that build is for and how to deploy it.
Disabling the policy engine as a library consumer
The same holds when Praxis crates are embedded. Each crate that reaches the
filter (praxis-proxy, praxis-proxy-protocol) depends on it without
defaults and exposes its own policy-engine feature, forwarding to the
filter’s. So:
- Depending on
praxis-proxy(the server as a library) withdefault-features = falseand naming the features you want gives a policy-free build; leaving defaults on gives the policy engine. - Depending on
praxis-proxy-protocolorpraxis-proxy-filterdirectly gives no policy engine unless you enablepolicy-engineon them (the filter’s own default is on, so setdefault-features = falseon that edge to keep it off).praxis-proxy-coreandpraxis-proxy-tlsnever pull it.
Cargo unions features across the whole dependency graph, so one crate anywhere
in your graph that depends on praxis-proxy-filter with its defaults turns
policy-engine back on for everyone, and the policy filter then becomes
nameable in config in a build believed to be policy-free. Verify with
cargo tree -e normal -i praxis-policy: no output means the policy engine
really is out of the build.
Feature summary
| Feature | Default | Enables | Turn it off / on when |
|---|---|---|---|
config-reload | on | Config-file and TLS-certificate hot-reload (filesystem watching). | Off for a static-config deployment: drops both watchers and the notify, arc-swap, and tokio dependencies they pull into the TLS crate. |
admin-api | on | The admin HTTP service: management API (/api/*), Prometheus /metrics, and /healthy + /ready. | Off when the proxy exposes no monitoring or management surface. The data path and background health checks are unaffected; only the HTTP endpoints go away. |
otel | off | OpenTelemetry / OTLP span export for traces. | On for distributed tracing. Pulls in a heavy opentelemetry + tonic dependency graph. |
policy-engine | on | The policy filter (Praxis Policy Engine: OPA-style route policy, JWT identity, token exchange). | Off for a deployment that does no policy-based authorization: it is the heaviest optional dependency, so dropping it is the largest single saving in build time and binary size. |
basic-auth-filter | off (experimental) | The basic_auth filter. | Dev and testing only. Slated for removal in favor of the policy engine (praxis-proxy/policy); prefer that for authentication. |
cloud-events-filter | off (experimental) | The cloud_events filter (serialize requests into CloudEvents and ship them to an HTTP receiver). | On for event export; delivery is best-effort. Adds chrono and url. |
upstream-binding | off (experimental) | Logical upstream binding: the router publishes the matched cluster as a request-wide binding that bound_upstream conditions and cluster_source: bound_upstream load balancers read. | On when a pipeline gates filters on the bound cluster’s application metadata or dispatches from the binding. Implied by the two features below. Off, those config forms are rejected at load time and the router never touches request extensions. |
iterative-request-router | off (experimental) | The iterative_request_router filter: a bounded loop of sub-requests for provider failover and agentic/tool loops. | On for callout and failover pipelines (the AI gateway relies on it). No extra dependencies; pulls in upstream-binding, since its steps dispatch from the binding. |
router-json-aliases | off (experimental) | The router filter’s JSON-alias body-routing groundwork. | Groundwork only: it is not wired into routing, and a route that sets json_aliases is rejected at build even with the feature on. Default builds do not accept the keys. |
bound-upstream-request-body | off (experimental) | The HttpFilter::on_bound_upstream_request_body hook, run once at the logical-binding barrier. | For out-of-tree filters that must inspect or rewrite the request body against the bound upstream; no in-tree filter uses it yet. Pulls in upstream-binding. |
chain-binding | off (experimental) | The register_chain_binding outbound-callout API (ChainBindingContext::bind_chain) and its authority-bound deferred credentials (PendingCredentials, DeferredCredential). | For out-of-tree callout filters; no in-tree consumer yet. |
spiffe | off (experimental) | SPIFFE X.509-SVID mTLS peer identity (the require_named listener mode) and the peer_identity_trust filter. | On for mTLS peer-identity authorization. Adds spiffe and x509-parser. |
dev | off | Developer convenience bundle (currently enables basic-auth-filter). | Local development builds. |
experimental | off | Marker feature set transitively by experimental features; drives a startup warning. | Not selected directly; it lights up when an experimental feature is enabled. |
Experimental features
Several features are experimental: each is off by default, each turns on the
experimental marker feature transitively, and enabling any of them makes the
server log experimental features are enabled that should not be used in production at startup. Do not run an experimental build in production.
basic-auth-filter(deprecated): thebasic_authfilter. Credentials live in plaintext config, so it is for development and testing only. Prefer the policy engine for authentication.cloud-events-filter: thecloud_eventsfilter, which serializes a request into a CloudEvent and ships it to a configured HTTP receiver. Delivery is best-effort and never changes the client response; review its limitations before relying on it.upstream-binding: logical upstream binding. With it, arouterin a pipeline that reads the binding publishes the matched cluster once per request,bound_upstreamconditions match on that cluster’s application metadata, and aload_balancerwithcluster_source: bound_upstreampicks an endpoint from it. Without it those two config forms fail validation and nothing in the request path changes. See Upstream Binding.iterative-request-router: theiterative_request_routerfilter, a bounded loop of sequential sub-requests through named step pipelines. It powers provider failover and LLM agentic/tool loops and is the flagship consumer path for the AI gateway. Its streaming multi-step machine is high-complexity code that is still stabilizing.router-json-aliases: groundwork for routing on a JSON request-body field through therouterfilter. The matching primitives exist but are not wired into request routing, so a route that setsjson_aliasesis rejected at build even with the feature on. It is kept behind the flag for a future implementation; default builds do not carry thejson_aliaseskeys at all.bound-upstream-request-body: the once-per-request bound-upstream request-body hook (bound_upstream_request_body_accessandon_bound_upstream_request_bodyonHttpFilter). It runs right after the bindingrouterfreezes the request’s logical upstream binding, over the fully buffered body, and a read-write participant’s output becomes the body forwarded, retried, and handed to the IRR. Logical binding itself is not gated; only this hook is. It has no in-tree consumer yet.chain-binding: theregister_chain_bindingextension API andChainBindingContext::bind_chain, together with the authority-bound deferred-credential channel (PendingCredentials/DeferredCredential) that injects a secret into an outbound sub-request only when the resolved destination matches the authority the credential was issued for. This is the outbound-callout mechanism; it has no in-tree consumer yet and exists for out-of-tree callout filters.spiffe: SPIFFE X.509-SVID mutual-TLS peer identity, including therequire_namedlistener client-cert mode, plus thepeer_identity_trustfilter that authorizes clients by mTLS peer identity. Note thatpeer_identity_trustworks with any mTLS client certificate, not only SPIFFE, so a non-SPIFFE mTLS deployment must still build withspiffeto use it.
Notes
- Runtime still gates behavior. Building with
admin-apidoes not start the admin endpoints; they bind only whenadmin.addressis configured. A listener’shot_reload: truekey takes effect only when the binary was built withconfig-reload; otherwise the certificate is served statically and a startup warning is logged. - The memory allocator is not a feature. Praxis targets Linux and always
uses
tikv-jemallocator; there is no build toggle for it. - Where the savings are. Dropping
policy-engine,config-reload,admin-api, andotelis what trims the dependency tree and binary size,policy-engineby the widest margin. Most filters are always compiled in and share dependencies with the core proxy, so gating them individually would not remove a crate. The experimental filter gates (upstream-binding,iterative-request-router,chain-binding,router-json-aliases,bound-upstream-request-body) exist to keep unfinished or not-for-production surface out of default builds rather than to save a crate;spiffeandcloud-events-filterdo additionally drop dependencies (spiffe+x509-parser, andchrono+urlrespectively).
See also
- Filter Reference: the per-filter
Featurecolumn shows which filters require a cargo feature. - Observability: metrics and tracing, gated by
admin-apiandotel. - TLS: the runtime
hot_reloadlistener key, gated byconfig-reload. - Getting Started: the build and test workflow.