Skip to content

Spikard Documentation

Spikard is a polyglot API toolkit with a Rust core and first-class bindings for Python, TypeScript/Node, Ruby, PHP, and Rust. It keeps routing, middleware, validation, and streaming semantics identical across languages so teams can mix runtimes without relearning frameworks.

Hello Route (pick a binding)

from spikard import Spikard
from spikard.config import ServerConfig
from msgspec import Struct

class User(Struct):
    id: int
    name: str

app = Spikard()

@app.get("/users/{id:int}")
async def get_user(id: int) -> User:
    return User(id=id, name="Alice")

if __name__ == "__main__":
    app.run(config=ServerConfig(port=8000))
import { Spikard, type Request } from "spikard";
import { z } from "zod";

const UserSchema = z.object({ id: z.number(), name: z.string() });
type User = z.infer<typeof UserSchema>;

const app = new Spikard();

app.addRoute(
  { method: "GET", path: "/users/:id", handler_name: "getUser", is_async: true },
  async (req: Request): Promise<User> => {
    const id = Number(req.params["id"] ?? 0);
    return { id, name: "Alice" };
  },
);

if (require.main === module) {
  app.run({ port: 8000 });
}
require "spikard"

app = Spikard::App.new

app.get("/users/:id") do |params, _query, _body|
  { id: params[:id].to_i, name: "Alice" }
end

app.run(config: { port: 8000 })
<?php

declare(strict_types=1);

use Spikard\App;
use Spikard\Attributes\Get;
use Spikard\Config\ServerConfig;
use Spikard\Http\Response;

final class HelloController
{
    #[Get('/')]
    public function index(): Response
    {
        return Response::text('Hello, World!');
    }

    #[Get('/hello/{name}')]
    public function greet(\Spikard\Http\Request $request): Response
    {
        $name = $request->pathParams['name'];
        return Response::json(['message' => "Hello, {$name}!"]);
    }
}

$app = (new App(new ServerConfig(port: 8000)))
    ->registerController(new HelloController());

$app->run();
use axum::response::Json;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use spikard::{get, App, RequestContext};

#[derive(Serialize, Deserialize, JsonSchema)]
struct User {
    id: i64,
    name: String,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut app = App::new();

    app.route(get("/users/:id"), |ctx: RequestContext| async move {
        let id = ctx.path_param("id").unwrap_or("0").parse::<i64>().unwrap_or_default();
        Ok(Json(User { id, name: "Alice".into() }).into())
    })?;

    app.run().await?;
    Ok(())
}

Documentation Map

  • Getting Started – First route in each language plus how to run it.
  • Installation – Binding install commands and repo setup.
  • Guides – Routing, requests/responses, middleware, validation, dependency injection, deployment.
  • Concepts – Architecture, runtime model, validation, middleware, streaming internals.
  • Reference – Types, error semantics, and configuration surface.
  • CLI – Running the HTTP server and invoking generators from spikard-cli.
  • ADRs – Design history and rationale behind the runtime.

Getting Help

  • Questions / bugs: open an issue at github.com/Goldziher/spikard.
  • Chat: join the community Discord (https://discord.gg/pXxagNK2zN).
  • Contributing: see Contributing for coding standards, environment setup, and testing instructions.