# ntex: a composable networking framework for Rust beyond HTTP

> ntex is a Rust framework for typed asynchronous network services, with HTTP/1, HTTP/2, WebSocket, MQTT and AMQP support and a runtime you can swap. It suits teams that want protocol plumbing without a runtime lock-in.

**ntex-rs/ntex** — framework for composable networking services 

- Repository: https://github.com/ntex-rs/ntex
- Stars: 2,538 · Forks: 143
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/ntex-rs-ntex

## The problem ntex solves: protocol services, not just web handlers

Most Rust web frameworks assume the thing you are building is an HTTP application. ntex assumes the thing you are building is a network service, and HTTP is one of several protocols it might speak. The README describes the project as a framework for composable network services and lists HTTP/1, HTTP/2, WebSocket, MQTT 3 and 5, AMQP 1.0, TLS and runtime-independent I/O as the components it ships. That list is the whole pitch. A team writing a broker, an edge proxy, or a service that terminates WebSocket and then talks MQTT to a backend does not want to bolt three unrelated crates together and reconcile their I/O models. ntex gives them one service abstraction and one set of codecs to build on.

The audience is narrower than a general web framework's. If your program is a REST API with a database behind it, ntex will work, but the protocol breadth that justifies its design is wasted on you. The project is aimed at engineers who care about which reactor is underneath, who want typed service composition rather than a tower of middleware, and who are comfortable reading a workspace of fifteen crates instead of one crate with a large feature list. The minimum supported Rust version is 1.97, which the README states plainly and the workspace Cargo.toml repeats as rust-version. That is a recent toolchain, and it is a real constraint on older build images.

## How the workspace is split and how a request flows through it

The repository is a Cargo workspace, and the crate list is the architecture. ntex-io holds the I/O traits and the dispatcher plumbing. ntex-codec holds encoding and decoding. ntex-service defines the service abstraction that everything else composes against. ntex-http, ntex-router and ntex-server sit above those and provide the HTTP types, the routing table and the accept loop. ntex-tls wraps the TLS integrations, ntex-bytes handles buffers, and ntex-rt is the runtime layer that the feature flags switch. The top-level ntex crate is the facade that re-exports the pieces a user actually touches.

That layering is why runtime selection is a Cargo feature rather than a fork. The README states that without an explicit runtime feature, ntex uses its native single-threaded runtime and picks a platform I/O reactor automatically: io_uring on Linux with a fallback to polling, polling on other Unix platforms, and IOCP on Windows. The alternative runtimes are opt-in through the tokio and compio features, and the native reactor can be pinned explicitly with neon-polling, neon-uring or neon-iocp. The README adds one constraint that matters operationally: enable at most one runtime or native-reactor selection feature. Nothing in the build system enforces that for you, so a dependency graph that pulls in two of them is a problem you discover at compile time.

The service model itself is typed composition. A service is a value that takes a request and returns a future, and servers, routers and middleware all implement the same trait. The practical consequence is that a routing table and a raw TCP handler are the same kind of object to the framework, which is what makes the protocol list coherent rather than a bundle of separate libraries.

## Installing ntex and running a first server

ntex is published on crates.io, so the install step is a dependency line. The README gives this example, and the version is the major line rather than a pinned patch:

```toml
[dependencies]
ntex = "4"
```

To use a different runtime, the README shows the feature form. Adding tokio swaps the native runtime for the Tokio local runtime and its I/O driver:

```toml
[dependencies]
ntex = { version = "4", features = ["tokio"] }
```

The minimal server in the README combines a route macro with the runtime attribute macro. Note the README's own example contains a typo, wev::App::new() rather than web::App::new(), so copy the corrected form below or the code will not compile:

```rust
use ntex::{SharedCfg, web};

#[web::get("/")]
async fn index() -> &'static str {
    "Hello world!"
}

#[ntex::main]
async fn main() -> std::io::Result<()> {
    web::HttpServer::new(async |_| web::App::new().service(index))
        .bind("127.0.0.1:8080", SharedCfg::new("hello-world"))?
        .run()
        .await
}
```

Run it with cargo run and request 127.0.0.1:8080. You should see the string Hello world!. Two details in that snippet are worth reading twice. The bind call takes a SharedCfg carrying a name, which is how ntex labels a listener for configuration and shutdown purposes rather than a bare socket address. And the server factory is an async closure, which is the newer shape of the API and the reason the workspace requires a recent toolchain. If you are following an older ntex example from elsewhere, the closure form will not match.

## Where ntex is the wrong tool, and what the README does not tell you

The clearest limitation is that ntex is not a batteries-included web framework. The optional feature list is short: openssl and rustls for TLS integrations, compress for HTTP content compression, cookie for cookie support, url for URL parsing, and ws for WebSocket APIs which is on by default. There is no mention of a database layer, a template engine, a session store or an authentication middleware set. If your project needs those, you will be choosing and integrating them yourself, and the integration surface is the ntex service trait rather than a documented plugin API.

The README is also silent on several things an operator would ask about. There is no documented graceful shutdown procedure, no configuration file format, and no statement about how a running server behaves when a worker panics. The SharedCfg type appears in the hello-world example but the README does not explain what it controls beyond naming the listener. Those answers presumably live in the framework guide under docs/ or on docs.rs, but they are not in the README, and a reader deciding from the README alone should treat them as unverified.

The workspace Cargo.toml contains a detail that deserves attention from anyone building from source. The ntex-h2 dependency is patched to a Git branch, refine-api, rather than a published crate, even though the workspace also lists ntex-h2 = "4.1.0" in its dependency table. The patch section wins. That means a build from the repository's main branch pulls HTTP/2 support from a moving branch, not from a release. Consumers who depend on the published ntex crate from crates.io are not affected by the workspace patch, but anyone vendoring or forking the repository is. This is the kind of thing that turns into a confusing build failure months later, and the README does not mention it.

Finally, the runtime feature rule is a real failure mode. The README says to enable at most one runtime or native-reactor selection feature, and there is no compile-time guard described. A transitive dependency that enables compio while your own Cargo.toml enables tokio is a configuration error the build system will not catch for you.

## ntex versus actix: the difference is the service model and the runtime

The comparison people search for is ntex against actix, and the honest answer is that they share lineage and diverge on two axes. The first is the runtime. actix-web is built on the Tokio ecosystem and its own actor runtime. ntex treats the runtime as a feature flag and defaults to a native single-threaded runtime with a platform-selected reactor, offering tokio and compio as alternatives. If you have already standardized on Tokio and want one runtime in your process, actix is the simpler choice because there is nothing to select. If you want io_uring on Linux without adopting a completion-based runtime wholesale, ntex's neon-uring feature is the more direct route.

The second axis is scope. actix-web is a web framework; ntex is a networking framework that includes a web layer. The README's protocol list, MQTT 3 and 5, AMQP 1.0 alongside HTTP and WebSocket, is not something actix-web offers. For a service that terminates HTTP and then speaks AMQP to a message broker, ntex keeps both protocols inside one service abstraction and one I/O layer. With actix you would reach for separate crates and bridge them yourself.

The cost of that breadth is ecosystem. actix-web has a larger set of published extractors, middleware and third-party integrations, and more examples in circulation. ntex's own examples live in a separate repository, ntex-rs/examples, which the README links. If your problem is a conventional web application and you value the number of ready-made pieces, actix remains the lower-friction option. If your problem is a protocol service, ntex's design is aimed at exactly that case.

## Maintenance, release cadence and licence obligations

The repository is not archived, and the last push was on 2026-09-28. The workspace is published as separate crates with independent version numbers, and the recent releases show that: ntex-util v4.1.0 on 2026-09-21, ntex-service v5.0.1 on 2026-09-18, and ntex-tls v4.0.0 on 2026-09-15. Independent versioning is convenient for consumers who only need one crate, but it means an upgrade is rarely a single version bump. If you depend on ntex directly, the facade crate pulls in the component crates at the versions the workspace pins, and a major bump in ntex-service or ntex-tls can surface through it. Read ntex/CHANGES.md, which the README links, before moving the major version.

The licence situation is straightforward and worth stating precisely. The README says the project is licensed under either Apache License 2.0 or the MIT license, and the repository carries both LICENSE-APACHE and LICENSE-MIT at the top level. The workspace package metadata records license = "MIT OR Apache-2.0". This is the common dual-licence arrangement in the Rust ecosystem, and the choice is yours at the point of redistribution. The MIT option is the permissive one; Apache 2.0 adds an explicit patent grant. Nothing here is unusual, but if your organisation has a policy about patent clauses, the Apache 2.0 path is the one to review, and that review is a question for your legal team rather than for this article.

The upgrade cost to budget for is the toolchain floor. rust-version is 1.97 across the workspace, and the edition is 2024. A team on an older pinned compiler cannot adopt ntex without moving the toolchain first, which may be a larger change than the dependency itself.

## Conclusion

Adopt ntex when you are building a Rust service that speaks more than HTTP, or when you want the runtime to be a Cargo feature rather than a hard dependency. Do not adopt it if you want a batteries-included web framework with a large catalogue of extractors and middleware, or if you cannot move to Rust 1.97. Before committing, verify three things: that your chosen runtime feature compiles on your target platform, that the TLS backend you need is behind the openssl or rustls feature, and that the ntex-h2 dependency resolves from the branch the workspace pins rather than a published release.

## FAQ

### What is ntex in Rust?

ntex is a framework for composable network services written in Rust. The README states it provides a strongly typed component for building asynchronous network applications, including HTTP/1, HTTP/2, WebSocket, MQTT 3 and 5, AMQP 1.0, TLS, and runtime-independent I/O support.

### How do I install ntex and run a first server?

Add ntex = "4" to your dependencies and build the server shown in the README, which binds 127.0.0.1:8080 with a SharedCfg named hello-world and returns Hello world! for a GET request to the root path. Run it with cargo run and request that address.

### Which runtime does ntex use by default?

Without an explicit runtime feature, the README says ntex uses its native single-threaded runtime and selects a platform I/O reactor automatically: io_uring with a polling fallback on Linux, polling on other Unix platforms, and IOCP on Windows. The tokio and compio features switch to those runtimes instead.

### Can I enable more than one ntex runtime feature at once?

No. The README states that you should enable at most one runtime or native-reactor selection feature, and the documented options are tokio, compio, neon-polling, neon-uring and neon-iocp.

### What Rust version does ntex require?

The README gives a minimum supported Rust version of 1.97, and the workspace Cargo.toml sets rust-version = "1.97" with edition 2024.

### What licence is ntex released under?

The README says the project is licensed under either the Apache License, Version 2.0 or the MIT license, and the repository contains LICENSE-APACHE and LICENSE-MIT at the top level.

## Sources

- [Issues](https://github.com/ntex-rs/ntex/issues)
- [License: Apache-2.0](https://github.com/ntex-rs/ntex/blob/main/LICENSE)
- [ntex-rs/ntex on GitHub](https://github.com/ntex-rs/ntex)
- [README](https://github.com/ntex-rs/ntex/blob/main/README.md)
- [Releases](https://github.com/ntex-rs/ntex/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/ntex-rs-ntex
