@spikard/node
v0.10.2
Published
High-performance Node.js HTTP framework with Rust core. Type-safe routing, validation, middleware, and testing via napi-rs bindings.
Maintainers
Readme
Spikard for Node.js
High-performance HTTP framework for Node.js powered by a Rust core. Provides type-safe routing, validation, middleware, and testing via napi-rs bindings with zero-copy JSON conversion.
Features
- Rust-Powered Performance: Native speed via Tokio with dedicated thread pool
- Full TypeScript Support: Auto-generated types from napi-rs FFI bindings
- Zero-Copy JSON: Direct conversion without serialization overhead
- Tower-HTTP Middleware: Compression, rate limiting, timeouts, auth, CORS, request IDs
- Schema Validation: Zod integration for request/response validation
- Lifecycle Hooks: onRequest, preValidation, preHandler, onResponse, onError
- Testing: TestClient for HTTP, WebSocket, and SSE assertions
Installation
npm install @spikard/node
# or
pnpm add @spikard/nodeRequirements: Node.js 20+
For building from source, see the main README.
Quick Start
import { Spikard, type Request } from "@spikard/node";
import { z } from "zod";
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
const app = new Spikard();
const getUser = async (req: Request): Promise<User> => {
const id = Number(req.params["id"] ?? 0);
return { id, name: "Alice", email: "[email protected]" };
};
const createUser = async (req: Request): Promise<User> => {
return UserSchema.parse(req.json());
};
app.addRoute(
{ method: "GET", path: "/users/:id", handler_name: "getUser", is_async: true },
getUser,
);
app.addRoute(
{
method: "POST",
path: "/users",
handler_name: "createUser",
request_schema: UserSchema,
response_schema: UserSchema,
is_async: true,
},
createUser,
);
app.run({ port: 8000 });Routing & Schemas
Routes support Zod validation (recommended) or raw JSON Schema:
import { Spikard, type Request } from "@spikard/node";
import { z } from "zod";
const app = new Spikard();
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
});
const createUser = async (req: Request) => {
const user = req.json();
return { id: 1, ...user };
};
app.addRoute(
{
method: "POST",
path: "/users",
handler_name: "createUser",
request_schema: UserSchema,
response_schema: UserSchema,
is_async: true,
},
createUser,
);Supported HTTP methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, TRACE.
Dependency Injection
Register values or factories and access them via request.dependencies:
const app = new Spikard();
app.provide("config", { dbUrl: "postgresql://localhost/app" });
app.provide(
"dbPool",
async ({ config }) => ({ url: config.dbUrl, driver: "pool" }),
{ dependsOn: ["config"], singleton: true },
);
app.addRoute(
{ method: "GET", path: "/stats", handler_name: "stats", is_async: true },
async (req) => {
const deps = req.dependencies ?? {};
return { db: deps.dbPool?.url, env: deps.config?.dbUrl };
},
);Request Handling
Access query, path params, headers, cookies, and body:
get("/search")(async (req) => {
const q = req.query.q;
const id = req.params.id;
const auth = req.headers.authorization;
const session = req.cookies.session_id;
const body = req.json<{ name: string }>();
const form = req.form();
return { query: q, id };
});Advanced Features
File Uploads:
post("/upload")(async (req) => {
const body = req.json<{ file: UploadFile }>();
return { filename: body.file.filename, size: body.file.size };
});Streaming Responses:
get("/stream")(async function* () {
for (let i = 0; i < 10; i++) {
yield JSON.stringify({ count: i }) + "\n";
await new Promise(r => setTimeout(r, 100));
}
});Configuration
Configure middleware, compression, rate limiting, and authentication:
const config: ServerConfig = {
port: 8080,
workers: 4,
maxBodySize: 10 * 1024 * 1024,
requestTimeout: 30,
compression: { gzip: true, brotli: true, minSize: 1024 },
rateLimit: { perSecond: 100, burst: 200 },
jwtAuth: { secret: "key", algorithm: "HS256" },
};
app.run(config);See ServerConfig for all options.
Lifecycle Hooks
Execute code at key request/response stages:
app.onRequest(async (request) => {
console.log(`${request.method} ${request.path}`);
return request;
});
app.preValidation(async (request) => {
if (!request.headers["authorization"]) {
return { status: 401, body: { error: "Unauthorized" } };
}
return request;
});
app.onResponse(async (response) => {
response.headers["X-Frame-Options"] = "DENY";
return response;
});Testing
Use TestClient for HTTP, WebSocket, and SSE testing:
import { TestClient } from "@spikard/node";
import { expect } from "vitest";
const client = new TestClient(app);
// HTTP testing
const response = await client.get("/users/123");
expect(response.statusCode).toBe(200);
// WebSocket testing
const ws = await client.websocketConnect("/ws");
await ws.sendJson({ message: "hello" });
// SSE testing
const sse = await client.get("/events");Performance
Benchmarked across 34 workloads at 100 concurrency (methodology):
| Framework | Avg RPS | P50 (ms) | P99 (ms) | |-----------|--------:|----------:|----------:| | spikard (Bun) | 49,460 | 2.18 | 4.21 | | spikard (Node) | 46,160 | 2.18 | 3.35 | | elysia | 44,326 | 2.41 | 4.68 | | kito | 36,958 | 4.94 | 12.86 | | fastify | 19,167 | 6.74 | 14.76 | | morojs | 14,196 | 6.44 | 12.61 | | hono | 10,928 | 10.91 | 18.62 |
Spikard Node is 1.2x faster than Kito and 2.4x faster than Fastify.
Key optimizations:
- napi-rs zero-copy FFI bindings
- Dedicated Tokio runtime without blocking Node event loop
- Zero-copy JSON conversion (30-40% faster than JSON.parse)
- ThreadsafeFunction for async JavaScript callbacks
Examples
See examples/ for runnable projects. Code generation is supported for OpenAPI, GraphQL, AsyncAPI, and JSON-RPC specifications.
Documentation
Full documentation at spikard.dev. See also CONTRIBUTING.md.
Ecosystem
Spikard is available across multiple languages:
| Platform | Package | Status | |----------|---------|--------| | Node.js | @spikard/node | Stable | | Python | spikard | Stable | | Rust | spikard | Stable | | Ruby | spikard | Stable | | PHP | spikard/spikard | Stable |
License
MIT - See LICENSE for details
