server_native 0.1.3+1 copy "server_native: ^0.1.3+1" to clipboard
server_native: ^0.1.3+1 copied to clipboard

Rust-backed transport boot APIs for Dart HTTP servers.

server_native #

pub package pub points popularity likes server_native CI framework compat

server_native provides a Rust-backed HTTP server runtime for Dart with a dart:io-like programming model. For most server code, it is intended to be a drop-in replacement for HttpServer: keep the same request/response handling and swap only the bind bootstrap.

Table Of Contents #

Install #

dependencies:
  server_native: ^0.1.0

Quick Start (HttpServer Style) #

import 'dart:io';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  final server = await NativeHttpServer.bind('127.0.0.1', 8080, http3: false);

  await for (final request in server) {
    if (request.uri.path == '/health') {
      request.response
        ..statusCode = HttpStatus.ok
        ..headers.contentType = ContentType.json
        ..write('{"ok":true}');
      await request.response.close();
      continue;
    }

    request.response
      ..statusCode = HttpStatus.notFound
      ..headers.contentType = ContentType.text
      ..write('Not Found');
    await request.response.close();
  }
}

Drop-In HttpServer Replacement #

Existing HttpRequest/HttpResponse logic can remain unchanged. Typical migration:

  • before: HttpServer.bind(...)
  • after: NativeHttpServer.bind(...)
import 'dart:io';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  final HttpServer server = await NativeHttpServer.bind('127.0.0.1', 8080);
  await for (final request in server) {
    request.response
      ..statusCode = HttpStatus.ok
      ..write('drop-in ok');
    await request.response.close();
  }
}

Protocol Support (HTTP/1.1, HTTP/2, HTTP/3) #

  • HTTP/1.1: supported for plaintext and TLS servers.
  • HTTP/2: controlled explicitly with http2 (defaults to true).
  • HTTP/3: supported only with TLS and QUIC.

Notes:

  • TLS certificates do not implicitly force HTTP/2. If you want TLS + HTTP/1.1 only, set http2: false.
  • http3 options default to true, but HTTP/3 is automatically disabled for insecure (non-TLS) server boots.
  • If TLS cert/key are not configured, server boots run in HTTP/1.1 + optional HTTP/2 mode only (based on http2).

Address Semantics #

NativeHttpServer.bind() supports HttpServer-style address values:

  • '127.0.0.1', '::1', or any explicit host/IP
  • 'localhost' (loopback convenience)
  • 'any' (bind all interfaces)

You can also use:

  • NativeHttpServer.loopback(...)
  • NativeHttpServer.bindSecure(...)
  • NativeHttpServer.loopbackSecure(...)

Multi-Server Binding (NativeHttpServer.loopback) #

Bind one logical server across all loopback interfaces (127.0.0.1 and ::1 when available) with a single HttpServer stream:

import 'dart:io';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  final server = await NativeHttpServer.loopback(8080, http3: false);

  await for (final request in server) {
    request.response
      ..statusCode = HttpStatus.ok
      ..headers.contentType = ContentType.text
      ..write('loopback multi-server ok');
    await request.response.close();
  }
}

Multi-Server Binding Shortcut (localhost / any) #

Use bind() with localhost (loopback interfaces) or any (all interfaces) to get multi-interface binding through a single HttpServer:

import 'dart:io';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  final server = await NativeHttpServer.bind('localhost', 8080, http3: false);
  // Equivalent patterns:
  // final server = await NativeHttpServer.bind('any', 8080, http3: false);
  // final server = await NativeHttpServer.loopback(8080, http3: false);

  await for (final request in server) {
    request.response
      ..statusCode = HttpStatus.ok
      ..headers.contentType = ContentType.text
      ..write('localhost multi-server ok');
    await request.response.close();
  }
}

Callback Multi-Server Binding (NativeMultiServer) #

Use NativeMultiServer when you want callback-style routing and http_multi_server-style bind semantics:

import 'dart:io';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  await NativeMultiServer.bind(
    (request) async {
      request.response
        ..statusCode = HttpStatus.ok
        ..headers.contentType = ContentType.text
        ..write('native multi bind ok');
      await request.response.close();
    },
    'localhost',
    8080,
    http3: false,
  );
}

Explicit Multi-Bind List (NativeServerBind) #

Use NativeServerBind with serveNativeMulti/serveSecureNativeMulti for fully explicit listener lists:

import 'dart:io';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  await serveNativeMulti(
    (request) async {
      request.response
        ..statusCode = HttpStatus.ok
        ..headers.contentType = ContentType.text
        ..write('explicit binds ok');
      await request.response.close();
    },
    binds: const <NativeServerBind>[
      NativeServerBind(host: '127.0.0.1', port: 8080),
      NativeServerBind(host: '::1', port: 8080),
    ],
    http3: false,
  );
}

TLS / HTTPS (Optional HTTP/3) #

import 'dart:io';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  final server = await NativeHttpServer.bindSecure(
    '127.0.0.1',
    8443,
    certificatePath: 'cert.pem',
    keyPath: 'key.pem',
    http2: true,
    http3: true,
  );

  await for (final request in server) {
    request.response
      ..statusCode = HttpStatus.ok
      ..headers.contentType = ContentType.text
      ..write('secure ok');
    await request.response.close();
  }
}

Callback API (HttpRequest) #

If you prefer a callback instead of a server stream:

import 'dart:io';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  await serveNativeHttp((request) async {
    request.response
      ..statusCode = HttpStatus.ok
      ..headers.contentType = ContentType.text
      ..write('hello');
    await request.response.close();
  }, host: '127.0.0.1', port: 8080, http3: false);
}

nativeCallback defaults to true for NativeHttpServer and serveNative* HttpRequest APIs, which means direct FFI callback transport is used by default. Set nativeCallback: false to force bridge socket transport. WebSocket upgrade is supported in either mode.

Direct Handler API (NativeDirectRequest) #

This mode gives direct method/path/header/body access without HttpRequest.

import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  await serveNativeDirect((request) async {
    if (request.method == 'GET' && request.path == '/health') {
      return NativeDirectResponse.bytes(
        headers: const [
          MapEntry(HttpHeaders.contentTypeHeader, 'application/json'),
        ],
        bodyBytes: Uint8List.fromList(utf8.encode('{"ok":true}')),
      );
    }

    final body = await utf8.decoder.bind(request.body).join();
    return NativeDirectResponse.bytes(
      status: HttpStatus.ok,
      headers: const [
        MapEntry(HttpHeaders.contentTypeHeader, 'text/plain; charset=utf-8'),
      ],
      bodyBytes: Uint8List.fromList(utf8.encode('echo: $body')),
    );
  }, host: '127.0.0.1', port: 8080, http3: false);
}

For lowest overhead callback routing, enable native callback mode:

import 'dart:io';
import 'dart:typed_data';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  await serveNativeDirect((request) async {
    return NativeDirectResponse.bytes(
      status: HttpStatus.ok,
      headers: const [
        MapEntry(HttpHeaders.contentTypeHeader, 'text/plain; charset=utf-8'),
      ],
      bodyBytes: Uint8List.fromList('ok'.codeUnits),
    );
  }, host: '127.0.0.1', port: 8080, nativeDirect: true);
}

Graceful Shutdown #

All boot helpers accept shutdownSignal.

import 'dart:async';
import 'dart:io';

import 'package:server_native/server_native.dart';

Future<void> main() async {
  final shutdown = Completer<void>();
  final serveFuture = serveNativeHttp((request) async {
    request.response
      ..statusCode = HttpStatus.ok
      ..write('bye');
    await request.response.close();
  }, host: '127.0.0.1', port: 8080, shutdownSignal: shutdown.future);

  // Call this from your signal handler / lifecycle hook.
  shutdown.complete();
  await serveFuture;
}

DevTools Profiling Example #

Use the included profiling target:

dart --observe example/devtools_profile_server.dart --mode=direct --port=8080

Modes:

  • --mode=direct for direct handler path
  • --mode=http for HttpRequest path

Framework Benchmarks #

Framework transport benchmarks live in benchmark/:

dart run benchmark/framework_transport_benchmark.dart --framework=all

Latest harness snapshot (February 19, 2026; requests=2500, concurrency=64, warmup=300, iterations=25):

Note: these values were measured on a local development machine and are intended for relative comparison. See benchmark/README.md for full test machine specs and run context.

Mode meaning in this table:

  • nativeCallback=true: NativeHttpServer uses direct FFI callback handling (bridge socket bypassed).
  • nativeCallback=false: NativeHttpServer uses the bridge socket/frame transport between Rust and Dart.
Mode Top result req/s p95
nativeCallback=true native_direct_rust 12362 6.34 ms
nativeCallback=false native_direct_rust 12656 6.17 ms

Framework pair highlights from the same harness:

Framework *_io *_native (nativeCallback=true) *_native (nativeCallback=false)
dart:io 7703 req/s, p95 9.72 ms 8370 req/s, p95 9.05 ms 7565 req/s, p95 10.60 ms
routed 5703 req/s, p95 12.51 ms 7110 req/s, p95 10.88 ms 6392 req/s, p95 11.93 ms
relic 5073 req/s, p95 14.46 ms 6823 req/s, p95 11.31 ms 5990 req/s, p95 12.73 ms
shelf 5181 req/s, p95 14.08 ms 6524 req/s, p95 11.66 ms 5843 req/s, p95 13.07 ms

See benchmark/README.md for full result tables, options, and case labels.

Framework Compatibility Suites (Local + CI) #

Use the compatibility harness to clone/update external frameworks, apply server_native integration patches, and run their full test suites in both transport modes:

  • SERVER_NATIVE_COMPAT=false (io): framework binds with dart:io HttpServer
  • SERVER_NATIVE_COMPAT=true (native): framework binds with NativeHttpServer

Run locally from repo root:

dart run packages/server_native/tool/framework_compat.dart \
  --framework=all \
  --mode=both \
  --fresh \
  --json-output=.dart_tool/server_native/framework_compat/report.json

Run a single framework:

dart run packages/server_native/tool/framework_compat.dart --framework=shelf --mode=both --fresh

CI workflow:

  • .github/workflows/server_native_framework_compat.yml

The workflow runs the same harness command and uploads a JSON result artifact.

Dart SDK HttpServer Compatibility Tests #

server_native includes a Dart SDK-derived compatibility suite in:

  • test/sdk_http_server_compat_test.dart

Run it directly:

dart test test/sdk_http_server_compat_test.dart

The suite is ported from SDK standalone IO HttpServer tests and currently contains:

  • default response-header behavior
  • content-type charset encoding behavior for response.write
  • connection-header/persistent-connection behavior
  • content-length mismatch error behavior (response.done)
  • shared bind behavior (shared: true)

Some native parity cases are explicitly skipped with a reason string until the corresponding behavior matches dart:io. Those skip reasons serve as an up-to-date checklist for remaining HttpServer parity work.

Native Bindings #

If you changed Rust FFI symbols/structs, regenerate bindings:

dart run tool/generate_ffi.dart

If you bump pubspec.yaml version, regenerate prebuilt release metadata:

dart run tool/generate_prebuilt_release.dart

Prebuilt Native Artifacts #

Cross-platform artifacts are built by:

  • .github/workflows/server_native_prebuilt.yml

CI build output is staged under:

  • packages/server_native/native/prebuilt/<platform>/

Artifact naming:

  • server_native-<platform>.tar.gz

Prebuilt binary release tags are separate from Dart package releases:

  • server-native-prebuilt-v*

Current platform labels:

  • linux-x64, linux-arm64
  • macos-arm64, macos-x64
  • windows-x64, windows-arm64
  • android-arm64, android-armv7, android-x64
  • ios-arm64, ios-sim-arm64, ios-sim-x64

Pull host prebuilts into your project:

dart run server_native:setup

setup is optional. Build hooks now auto-download the package-matched prebuilt release into .dart_tool/server_native/prebuilt/<tag>/<platform>/ when no local prebuilt is available.

This defaults to the prebuilt tag generated from the local server_native package version (for example server-native-prebuilt-v0.1.2). To auto-select the newest available prebuilt release instead, use:

dart run server_native:setup --tag latest

Pull a specific release tag and platform:

dart run server_native:setup --tag server-native-prebuilt-v0.1.2 --platform linux-x64

Downloaded files are extracted to:

  • .dart_tool/server_native/prebuilt/<tag>/<platform>/

Build hook prebuilt lookup order:

  1. SERVER_NATIVE_PREBUILT (absolute path to a library file)
  2. <project-root>/.dart_tool/server_native/prebuilt/<tag>/<platform>/<library>
  3. <project-root>/.dart_tool/server_native/prebuilt/<platform>/<library> (legacy fallback)
  4. <repo-root>/.dart_tool/server_native/prebuilt/<tag>/<platform>/<library>
  5. <repo-root>/.dart_tool/server_native/prebuilt/<platform>/<library> (legacy fallback)
  6. <package-root>/native/prebuilt/<tag>/<platform>/<library> (packaged fallback)
  7. <package-root>/native/prebuilt/<platform>/<library> (legacy packaged fallback)
  8. <package-root>/native/<platform>/<library> (legacy packaged fallback)

If no prebuilt library is found, the hook falls back to Rust source build through native_toolchain_rust.

Troubleshooting #

If you see:

File modified during build. Build must be rerun.

Run the same command again once. This can happen on first native asset build.

8
likes
150
points
230
downloads

Publisher

unverified uploader

Weekly Downloads

Rust-backed transport boot APIs for Dart HTTP servers.

Homepage
Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

Funding

Consider supporting this project:

www.buymeacoffee.com

License

MIT (license)

Dependencies

archive, code_assets, contextual, ffi, hooks, native_toolchain_rust

More

Packages that depend on server_native