Note: As of v0.2.1, npm packages have moved to the
@spikardscope. Install withnpm install @spikard/nodeinstead ofnpm install spikard. See MIGRATION-0.2.1.md for details.
An experimental polyglot web development framework.
Spikard is a high-performance API toolkit built in Rust with bindings for Python, TypeScript, Ruby, PHP, and WebAssembly. Write REST APIs, JSON-RPC services, or Protobuf-based applications in the language you prefer—all sharing the same runtime, middleware, and validation engine.
The need for a single, high-performance toolbox across languages.
Working across multiple language ecosystems means learning different frameworks, different conventions, and different performance characteristics for each. Spikard provides one consistent API experience—whether you're writing Python for ML pipelines, TypeScript for frontends, Ruby for Rails integration, or Rust for maximum performance.
Same middleware. Same validation. Same correctness guarantees. Different languages.
Spikard IS:
- A batteries-included HTTP/API toolkit
- High-performance routing, middleware, and validation
- Protocol-agnostic (REST, JSON-RPC, Protobuf, GraphQL)
- Polyglot with consistent APIs across languages
- Built for microservices, APIs, and real-time services
Spikard IS NOT:
- A full-stack MVC framework (not Django, Rails, Laravel)
- A database ORM or query builder
- A template engine or view layer
- An admin interface or CMS
You bring your own:
- Database library (SQLAlchemy, Prisma, Sequel, Diesel, etc.)
- Template engine if needed (Jinja2, EJS, ERB)
- Frontend framework
Spikard focuses on being the best HTTP/API layer—everything from the socket to your handler. Database, templates, and full-stack concerns are intentionally out of scope.
- Python - Decorators, async/await, msgspec/Pydantic validation (README)
- TypeScript - Node.js/Bun (native) and Deno/Edge (WASM) (README)
- Ruby - Block-friendly routing, idiomatic patterns (README)
- PHP - PSR-compliant, background tasks, streaming, WebSocket/SSE support (README)
- Rust - Zero-cost native performance (README)
Planned:
- Go (exploring FFI options)
- C#, Java/Kotlin, Elixir (exploring)
We're open to additional language bindings—both FFI-based (like potential Go support) and native binding approaches. Community contributions welcome.
All language bindings share the same core features through the Rust runtime:
| Feature | Python | TypeScript | Ruby | PHP | Rust |
|---|---|---|---|---|---|
| HTTP/REST | ✅ | ✅ | ✅ | ✅ | ✅ |
| Path Parameters | ✅ | ✅ | ✅ | ✅ | ✅ |
| JSON Validation | ✅ | ✅ | ✅ | ✅ | ✅ |
| Background Tasks | ✅ | ✅ | ✅ | ✅ | ✅ |
| Dependency Injection | ✅ | ✅ | ✅ | ✅ | ✅ |
| Streaming | ✅ | ✅ | ✅ | ✅ | ✅ |
| WebSocket | ✅ | ✅ | ✅ | ✅ | ✅ |
| Server-Sent Events | ✅ | ✅ | ✅ | ✅ | ✅ |
| AsyncAPI Support | ✅ | ✅ | ✅ | ✅ | ✅ |
| OpenAPI Codegen | ✅ | ✅ | ✅ | ✅ | ✅ |
| Lifecycle Hooks | ✅ | ✅ | ✅ | ✅ | ✅ |
| Middleware Stack | ✅ | ✅ | ✅ | ✅ | ✅ |
All features are implemented once in Rust and exposed through thin, idiomatic bindings for each language.
Correctness First
- Follow web standards and IETF drafts (RFC 9457, JSON Schema Draft 2020-12, OpenAPI 3.1)
- Developed using TDD and Benchmark-Driven Development
- 400+ fixture-driven test scenarios ensure identical behavior across all languages
Simplicity
- Familiar APIs designed to feel natural in each language
- No reinventing concepts—leverage each ecosystem's best practices
Strong Validation
- JSON Schema validation for all requests and responses
- Strict typing enforced even in dynamic languages
- Native integration with language-specific validators
Build on Open Source
- Don't reinvent the wheel—use the best from each ecosystem
- Rust: axum, tower, tower-http, jsonschema
- Python: msgspec (required), PyO3 (with optional pydantic/attrs/dataclasses detection)
- TypeScript: Zod, napi-rs
- Ruby: Magnus FFI, RBS types (with optional dry-schema/dry-struct detection)
from spikard import App
from msgspec import Struct
class User(Struct):
id: int
name: str
app = App()
@app.get("/users/{id:int}")
async def get_user(id: int) -> User:
return User(id=id, name="Alice")
@app.post("/users")
async def create_user(user: User) -> User:
# Automatic validation via msgspec
return user
if __name__ == "__main__":
app.run(port=8000)import { Spikard, type Request } from "@spikard/node";
import { z } from "zod";
const UserSchema = z.object({
id: z.number(),
name: z.string(),
});
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" };
};
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 });require 'spikard'
app = Spikard::App.new
app.get('/users/:id') do |request|
user_id = request[:path_params]["id"].to_i
{ id: user_id, name: 'Alice' }
end
app.post('/users') do |request|
# request[:body] is validated when a schema is provided
request[:body]
end
app.run(port: 8000)<?php
use Spikard\App;
use Spikard\Config\ServerConfig;
use Spikard\Http\Request;
use Spikard\Http\Response;
use Spikard\Background\BackgroundTask;
$app = new App(new ServerConfig(port: 8000));
// Route with path parameter
$app = $app->addRoute('GET', '/users/{id}', function (Request $req) {
$id = (int)$req->pathParams['id'];
return Response::json(['id' => $id, 'name' => 'Alice']);
});
// JSON body with validation
$app = $app->addRoute('POST', '/users', function (Request $req) {
$user = $req->body;
// Run background task (e.g., send email)
BackgroundTask::run(function () use ($user) {
sendWelcomeEmail($user);
});
return Response::json($user, 201);
});
// Streaming response (SSE)
$app = $app->addRoute('GET', '/events', function () {
$generator = function (): Generator {
for ($i = 0; $i < 10; $i++) {
yield "data: " . json_encode(['count' => $i]) . "\n\n";
sleep(1);
}
};
return \Spikard\Http\StreamingResponse::sse($generator());
});
$app->run();use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use spikard::prelude::*;
#[derive(Serialize, Deserialize, JsonSchema)]
struct User {
id: i32,
name: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut app = App::new();
app.route(get("/users/:id"), |ctx: Context| async move {
let id: i32 = ctx
.path_param("id")
.unwrap_or("0")
.parse()
.unwrap_or_default();
Ok(Json(User { id, name: "Alice".to_string() }))
})?;
app.route(
post("/users").request_body::<User>().response_body::<User>(),
|ctx: Context| async move {
let user: User = ctx.json()?;
Ok(Json(user))
},
)?;
app.run().await?;
Ok(())
}Current:
- REST with typed routing (
/users/{id:uuid}) - HTTP/1.1 and HTTP/2
- Request/response streaming
- Server-Sent Events (SSE)
- WebSockets
- Multipart file uploads
- URL-encoded and JSON bodies
Coming Soon:
- JSON-RPC
- Protobuf with protoc support
- GraphQL (queries, mutations, subscriptions)
- CloudEvents (post v1.0)
- Queue protocols (AMQP, Kafka, etc.) (post v1.0)
- HTTP/3 (QUIC) (post v1.0)
All middleware is implemented in Rust and exposed through language bindings:
- Compression - gzip, brotli with configurable quality
- Rate Limiting - Token bucket, per-IP or global
- Request Timeouts - Configurable per-route or global
- Body Size Limits - Prevent abuse
- Request ID - UUID injection with custom headers
- CORS - RFC 6454 compliant
- Authentication - JWT and API Key support
- Static Files - ETag, Last-Modified, precompressed assets
JSON Schema:
- Draft 2020-12 support
- Automatic type coercion
- Comprehensive error messages (RFC 9457 Problem Details)
Language-Specific Power Tools:
Spikard integrates with native validation libraries in each language:
- Python: msgspec (required - zero-copy, fastest), with automatic detection of Pydantic v2, attrs, and dataclasses
- TypeScript: Zod (type inference and runtime validation)
- Ruby: Automatic detection of dry-schema, dry-struct when present
- PHP: Native array/object validation with PSR-7 HTTP message interfaces
- Rust: serde with schemars for JSON Schema generation
All validation approaches compile to the same JSON Schema contracts, ensuring cross-language consistency.
Fine-grained control over request processing:
onRequest- Before any processingpreValidation- Before schema validationpreHandler- After validation, before handleronResponse- Before sending responseonError- Error handling
Features:
- Zero-cost when not used (
Option<Arc<dyn Fn>>) - Can short-circuit the pipeline
- Full async support
- Container-based DI for services and dependencies
- Scoped injection (request cache, singleton, per-call)
- Language-idiomatic integration (Python
Provide, TypeScriptprovide, Rubyprovidewith keyword deps, PHPDependencyContainer, RustServerConfig::provide_*)
Code generation is a first-class citizen in Spikard.
OpenAPI 3.1/3.0:
spikard generate openapi --spec api.yaml --lang python --output ./appGenerates: REST routes, request/response types, validation, documentation
AsyncAPI 2.x/3.x:
spikard generate asyncapi --spec events.yaml --lang typescript --output ./appGenerates: SSE producers, WebSocket handlers, event schemas, documentation
Future Protocols:
- JSON-RPC spec → RPC handlers
- Protobuf (.proto files) → gRPC services
- GraphQL SDL → resolvers and types
- CloudEvents → event handlers (post v1.0)
All generated code includes:
- OpenAPI specs with complete schemas
- Markdown documentation
- Interactive API docs (Swagger UI, ReDoc)
- Code examples in all supported languages
Planned:
- MCP (Model Context Protocol) server for AI assistants
- Official Claude skills with up-to-date examples
- Context-aware code completion
- Automatic fixture generation from natural language
The CLI is designed to be AI-friendly: structured output, consistent patterns, and rich context for code generation tools.
Benchmarks on Apple M4 Pro (14-core, 48GB RAM) with 100 concurrent connections:
| Binding | Avg Throughput | Mean Latency | P99 Latency |
|---|---|---|---|
| Rust | 165,454 req/s | 0.60ms | 1.53ms |
| Python | 35,779 req/s | 7.44ms | - |
Key findings:
- Rust ~4.6x faster than Python, but Python still delivers 35k+ req/s
- Performance stable across payload sizes (86 bytes to 150KB)
- Low memory usage (~27MB for both)
- Zero-copy serialization (serde for Rust, msgspec for Python)
Node.js, Ruby, and WASM benchmarks coming soon.
What works:
- ✅ Core HTTP server with full middleware stack
- ✅ Python, TypeScript, Ruby, PHP, WASM, Rust bindings
- ✅ JSON validation with JSON Schema
- ✅ Code generation from OpenAPI and AsyncAPI
- ✅ Streaming, SSE, WebSockets
- ✅ Background tasks and dependency injection (all bindings)
- ✅ 400+ fixtures with comprehensive test coverage
- ✅ Benchmark harness for performance testing
Expectations:
- This is an initial experimental release (0.1)
- APIs will change as we gather feedback
- Not production-ready—use for evaluation only
- Breaking changes expected before v1.0
- HTTP/1.1 and HTTP/2 support
- REST routing with typed parameters
- JSON Schema validation
- Middleware stack (compression, rate limiting, CORS, auth, etc.)
- Streaming, SSE, WebSockets
- Lifecycle hooks
- OpenAPI 3.1 code generation
- AsyncAPI code generation
- Documentation generation
- Dependency Injection
- JSON-RPC protocol support
- Protobuf with protoc integration
- GraphQL support (queries, mutations, subscriptions)
- HTTP/3 (QUIC) support (post v1.0)
- CloudEvents support (post v1.0)
- Queue protocols (AMQP, Kafka) (post v1.0)
- Plugin/extension system
- Python (PyO3 + msgspec/Pydantic)
- TypeScript/Node.js (napi-rs + Zod/ArkType/Valibot)
- Ruby (Magnus + DrySchema)
- PHP (ext-php-rs + PSR standards)
- WebAssembly (wasm-bindgen)
- Rust (native)
- Go (Maybe?)
- C# (Maybe?)
- Java/Kotlin (Maybe?)
- Elixir (Maybe?)
- Python: msgspec (required), with auto-detection of Pydantic v2, attrs, dataclasses
- TypeScript: Zod
- Ruby: Auto-detection of dry-schema, dry-struct
- TypeScript: ArkType, Valibot, TypeBox, Effect
- Ruby: dry-validation, ActiveModel
- Fixture-driven testing (400+ scenarios)
- CLI for code generation
- OpenAPI and AsyncAPI support
- Documentation generation
- MCP server (as part of the CLI)
- Official Claude skills
- Comprehensive documentation site
- Example applications library
- Benchmark harness (profiling support builtin)
- Zero-copy serialization paths
- API stability guarantees
Language-specific packages:
pip install spikardSee Python README for more details.
npm install @spikard/node
# or with pnpm
pnpm add @spikard/nodeSee Node.js README for more details.
gem install spikardSee Ruby README for more details.
composer require spikard/spikardSee PHP README for more details.
npm install @spikard/wasm
# or
pnpm add @spikard/wasmSee WASM README for more details.
cargo add spikardSee Rust README for more details.
Requirements:
- Rust 1.80+ (
rustup) - Python 3.11+ with
uvorpip - Node.js 20+ with
pnpm - Ruby 3.2+ with
bundler - PHP 8.2+ with
composer
Quick Start:
# Clone repository
git clone https://github.com/Goldziher/spikard.git
cd spikard
# Install dependencies
pnpm install
bundle install
uv sync
composer install
# Build bindings
task build:py # Python
task build:node # Node.js
task build:ruby # Ruby
task build:php # PHP
task build:wasm # WebAssembly
task build:rust # Rust
# Run tests
task test
# Try an example
cd examples/python
python server.pySee CONTRIBUTING.md for detailed development setup.
-
Language-Specific READMEs:
-
Architecture Decision Records (ADRs): docs/adr/
- Design decisions, middleware architecture, validation strategy
-
Contributing: CONTRIBUTING.md
- Development setup, testing, benchmarking
-
Comprehensive Documentation: (Coming soon)
We welcome contributions! See CONTRIBUTING.md for:
- Development workflow
- Testing and fixture-driven development
- Benchmarking methodology
- Code standards
- How to add language bindings
Ways to help:
- Try it out and report issues
- Share benchmark results
- Contribute language bindings
- Add example applications
- Improve documentation
MIT License - see the LICENSE file for details.
Copyright (c) 2025 Na'aman Hirschfeld
Rust:
- Axum - Type-safe extractors, ergonomic routing, and Tower middleware integration
- Tower - Composable middleware and service abstractions
Python:
- Litestar - Declarative API design, lifecycle hooks, and dependency injection patterns
- FastAPI - Common conventions, OpenAPI integration, and developer experience
- Robyn - Rust-Python binding techniques and async bridge design
TypeScript/Node:
- Fastify - Opt-in performance philosophy and plugin architecture
- Hono - Clean routing API and edge runtime support
Ruby:
- Roda - Routing tree design and minimal overhead approach
- Hanami - Component architecture and clean abstractions
- Rack - Middleware pipeline and HTTP abstraction
Spikard - One toolbox. Many languages.