uWebSockets server based on web standards APIs
- Simple and lightweight
- Blazingly fast 🔥
- Support for web standards based frameworks
- Supports
HTTP,SSL, andHTTP/3 - Support for streaming request and response bodies
- Handles backpressure
- Graceful shutdown and connection draining
- Signal handling
- Support for handling uncaught exceptions
- Serve static middleware
- Compression support:
br,gzip,zstd,deflate - Support for in-memory caching
- 0 external dependencies
Lightweight server implementation based on uWebSockets. Originally designed with the Hono framework in mind, it can also be used with Elysia or any other framework/runtime that supports web standards APIs.
Add uws-server as a dependency and install via npm
npm install uws-server@danmasta/uws-server --saveInstall a specific version
npm install uws-server@danmasta/uws-server#semver:^v0.0.0 --saveSee documentation regarding git dependencies here
Install uWebSockets
npm install uws@uNetworking/uWebSockets.js --saveImport functions
import { serve, serveStatic } from 'uws-server';Usage with Hono is similar to the node-server adapter:
import { Hono } from 'hono';
const app = new Hono();
serve({
fetch: app.fetch
});Usage with Elysia is also very simple, just pass the fetch handler to serve:
import { Elysia } from 'elysia';
const app = new Elysia();
serve({
fetch: app.fetch
});Any other framework that supports web standards APIs can also be used. You only need to provide a fetch function that accepts a Request object, and returns a Response object:
function fetch (request) {
return new Response(...);
}
serve({
fetch
});Base entrypoint for initializing a uWS server instance. You can use the Server class directly, or use the factory function serve
import { Server, serve } from 'uws-server';serve(opts?, fn?(info, server));| Name | Type | Description |
|---|---|---|
fetch |
function |
Function to use when generating a Response. Default is undefined |
bind |
string |
Address to bind server to. This can be a wildcard address (::, 0.0.0.0), loopback address (127.0.0.1, ::1, localhost), or a specific interface address (10.0.0.1). Default is :: |
port |
number |
Port to listen on (undefined or null will allocate a random port). Default is undefined |
defaultHost |
string |
Default host to use for requests without a host header. Default is undefined |
ssl |
boolean |
Enable SSL. You will need to supply server options for the key/cert configuration. Default is false |
http3 |
boolean |
Enable HTTP/3. This is experimental. Default is false |
createServer |
function |
Custom function to use when generating the server instance. Default is undefined |
server |
object |
Custom AppOptions to pass to uWebSockets on server instance creation. Default is undefined |
uws |
object |
uWebSockets default export to use for generating server instances. If this is not set, serve will attempt to load via dynamic import. Default is undefined |
globals |
boolean |
This library borrows the concept of lightweight Request and Response classes from Hono, in which the Request and Repsonse objects are lazily created when accessed. If true, this will enable overriding of the built-in Request and Response classes. *This functionality is subject to change or removal. Default is true |
showError |
boolean |
Include error message in the response text for uncaught errors during the Request/Response flow. Default is true |
showStack |
boolean |
Include error stack trace in the response text for uncaught errors during the Request/Response flow. Default is false |
log |
object |
Log implementation to use. Custom loggers should at least implement the methods: info, error, warn, debug, and support printf style string formatting. Default is console |
timeout |
number |
Maximum time to wait for connections to drain during graceful shutdown in milliseconds. Default is 10000 |
listen |
boolean |
Start listen socket on server create. Default is true |
signals |
string|string[] |
Signals to listen to for graceful shutdown. Default is ['SIGINT', 'SIGTERM'] |
exitOnSignal |
boolean |
Enable exiting process after signal shutdown. Default is true |
handleUncaught |
boolean |
Enable handling uncaught exceptions and rejections. Default is true |
exitOnUncaught |
boolean |
Enable exiting process after uncaught exception or rejection. Default is true |
shutdown |
function|promise |
Handlers to execute on graceful shutdown. Handlers can be functions or promises, they are executed in order and awaited. Default is undefined |
Middleware for serving static files from the file system. You can use the ServeStatic class directly, or use the factory function serveStatic
import { ServeStatic, serveStatic } from 'uws-server';serveStatic(root?, opts?);| Name | Type | Description |
|---|---|---|
cwd |
string |
Base path to resolve relative paths from. Default is process.cwd |
root |
string |
Directory to serve files from. Default is undefined |
normalize |
string |
String to remove from beginning of request paths. If you mounted the middleware at /static/*, Hono will include /static in the request path. Setting this option to /static would remove the leading mount point. Default is undefined |
index |
boolean |
Enable serving index.html if a matched path is a directory. Default is false |
rewrite |
function(path) |
Function to use for rewriting file paths before lookup. Default is undefined |
lastModified |
boolean |
Enable setting the last-modified header. Default is true |
nosniff |
boolean |
Enable setting the x-content-type-options header. Default is true |
cache |
boolean |
Enable in-memory LRU cache for files. Default is false |
max |
number |
Max entry size of LRU cache. Default is 1024 |
maxSize |
number |
Max allowed size of files to cache in bytes. Files larger than this are not cached and always streamed from disk. Default is 1048576 (1MB) |
encodings |
string[]|boolean |
Enable compression support. Should be a list of compression algorithms in order of preference. Setting to false will disable compression support. Default is ['br', 'gzip', 'zstd', 'deflate'] |
range |
boolean |
Enable support for range requests. Default is true |
fallthrough |
boolean |
Allow not found requests to continue downstream to other handlers. Default is false |
found |
function(c, path) |
Function to call for each found request. Return value is ignored. Default is undefined |
notFound |
function(c, path) |
Function to call for each not found request. Return value will be used as the 404 response. Default is undefined |
Quick benchmark to a simple endpoint that returns zero bytes with a 200 status code on my local machine (i7, wsl2, node v22.15.0):
bombardier --fasthttp -l -d 10s -c 128 "http://localhost:8080/health"
Statistics Avg Stdev Max
Reqs/sec 142158.70 17551.53 176572.69
Latency 0.90ms 768.26us 146.56ms
Latency Distribution
50% 777.00us
75% 1.11ms
90% 1.50ms
95% 1.86ms
99% 2.95ms
HTTP codes:
1xx - 0, 2xx - 1414384, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 21.18MB/s
bombardier --fasthttp -l -d 10s -c 128 "http://localhost:8080/health"
Statistics Avg Stdev Max
Reqs/sec 106615.78 13159.17 122120.10
Latency 1.21ms 1.10ms 129.36ms
Latency Distribution
50% 1.10ms
75% 1.44ms
90% 1.88ms
95% 2.17ms
99% 2.92ms
HTTP codes:
1xx - 0, 2xx - 1059614, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 22.13MB/s
bombardier --fasthttp -l -d 10s -c 128 "http://localhost:8080/health"
Statistics Avg Stdev Max
Reqs/sec 58095.49 3815.93 62637.02
Latency 2.22ms 1.48ms 129.70ms
Latency Distribution
50% 2.00ms
75% 2.21ms
90% 2.77ms
95% 3.88ms
99% 4.42ms
HTTP codes:
1xx - 0, 2xx - 575371, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 11.85MB/s
bombardier --fasthttp -l -d 10s -c 128 "http://localhost:8080/health"
Statistics Avg Stdev Max
Reqs/sec 18794.08 1940.57 21559.27
Latency 6.85ms 2.55ms 210.50ms
Latency Distribution
50% 6.30ms
75% 7.22ms
90% 8.05ms
95% 8.90ms
99% 12.98ms
HTTP codes:
1xx - 0, 2xx - 186828, 3xx - 0, 4xx - 0, 5xx - 0
others - 0
Throughput: 5.29MB/s
| Name | Req/s (avg) | Req/s (max) | p99 | Multiplier |
|---|---|---|---|---|
| Hono | 142,158.70 | 176,572.69 | 2.95ms | 7.56x-8.19x |
| H3 | 106,615.78 | 122,120.10 | 2.92ms | 5.67x-5.66x |
| Elysia | 58,095.49 | 62,637.02 | 4.42ms | 3.09x-2.90x |
| Express | 18,794.08 | 21,559.27 | 12.98ms | 1x-1x |
Elysia with uWS sees 3x improvement over Express. While H3 with uWS sees over 5x improvement, and Hono with uWS sees over 7x improvement
Serve a Hono app instance on port 8080, and static assets from the build directory at the /static mount path
import { serve, serveStatic } from 'uws-server';
import { Hono } from 'hono';
const app = new Hono();
app.use('/static/*', serveStatic('build', {
normalize: '/static',
cache: true
}));
serve({
fetch: app.fetch,
port: 8080
});Generate custom uWebSockets server instances
import { serve } from 'uws-server';
import uws from 'uws';
function createServer () {
return uws.App();
}
serve({
createServer,
uws
});Tests are currently run using mocha and chai. To execute tests run make test. To generate unit test coverage reports run make coverage
If you have any questions feel free to get in touch