┌─────────────────────────────────────────────────────────────┐
│ │
│ REQUEST ──► ROUTE ──► HANDLER ──► RENDER ──► RESPONSE │
│ │
│ No DI. No middleware. No magic. Just metal. │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Kestrel │ │ Metadata │ │ Binary │ │ Template │ │
│ │ HTTP/SSL │─►│ Driven │─►│ Wire │─►│ Streamer │ │
│ │ Only │ │ Routing │ │ Format │ │ PipeIO │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Independent research project — developed in a personal capacity. No Microsoft compute, code, or confidential information are used or developed within.
This project is an attempt to build a vertically integrated web-reporting-business-query-database-distributed compute fabric on top of .NET, targeting maximum possible performance by taking a fundamentally different approach from existing web servers. It explores an alternative compute paradigm by reducing the development model to a simple, explicit state machine driven by metadata rather than layered abstractions.
The system deliberately rejects dependency injection, middleware pipelines, and convention-based abstractions in favour of explicit, deterministic control over execution flow. Each request is processed through a well-defined lifecycle rather than implicit framework behaviour or chained components. This removes hidden cost, reduces cognitive overhead, and ensures that what executes is exactly what is written.
A custom binary serialization format is used in place of JSON for internal data handling, eliminating unnecessary encoding overhead, reducing allocations, and enabling predictable, high-performance data access patterns. Where JSON interoperability is required, it is handled via a metadata-driven streaming transformation layer operating at wire speed, completely avoiding reflection-based serialization. Data is projected directly to and from the wire format with minimal overhead, preserving performance while maintaining compatibility with external systems.
The design prioritises mechanical sympathy, transparency, and raw performance over flexibility or developer convenience. All behaviours are explicit, all costs are visible, and the system is constructed from first principles rather than derived from existing framework conventions.
A raw, high-performance web framework built on bare-metal ASP.NET Core.
No MVC. No middleware pipeline. No DI containers. No Razor. No magic.
Just Kestrel, explicit routing, streaming HTML templates, a custom binary serializer, and total control.
📚 Full Documentation Index → | 🗺️ Architecture Diagrams →
BareMetalWeb is a lean, mean web server that uses ASP.NET Core only for HTTP/SSL — everything else is built from scratch for minimalism, performance, and clarity. Think classic-era .ashx handlers and HttpModules reborn in modern .NET 10.
- Explicit data-driven routing — routes are mutable at runtime, no convention magic
- Streaming HTML templates —
{{token}}replacement,{{Loop%%key}}/{{For%%i|from|to|step}}blocks viaPipeReader/PipeWriter - Custom binary serializer — fast, compact session and data storage with schema versioning
- Pluggable data storage — file-based binary provider by default, swap in anything via interfaces
- Auto-scaffolded CRUD — decorate a class with
[DataEntity]and get REST API + admin UI for free - Built-in auth — session cookies, MFA, Service Principal API keys (PBKDF2 hashed)
- Request throttling — per-IP token bucket rate limiting
- Strong CSP & security — secure headers, cookie hardening, request validation
- Async buffered logging — per-minute log files, non-blocking, clean shutdown records
- Static file serving — streaming with ETag/Last-Modified/Cache-Control, MIME mapping
- Reverse proxy — route-based forwarding with cookie stripping
- Native AOT CLI tool —
metalbinary for managing any BareMetalWeb instance from the terminal
# Prerequisites: .NET 10 SDK
dotnet --version # should be 10.x
# Build
dotnet build
# Run tests
dotnet test --no-build
# Run the server
cd BareMetalWeb.Host
dotnet run
# → BareMetalWeb server is ready — PID 12345 — listening for requests on http://localhost:5232The first run triggers the Out-of-Box Experience (OOBE) setup wizard at http://localhost:5232/setup where you create the admin account and seed sample data.
| Project | Purpose |
|---|---|
BareMetalWeb.Host |
Kestrel server, routes, request handlers |
BareMetalWeb.Core |
Shared models, enums, static assets (JS/CSS/templates) |
BareMetalWeb.Data |
Storage, serialization, scaffolding, settings, auth |
BareMetalWeb.Rendering |
SSR HTML fragment rendering |
BareMetalWeb.Runtime |
Runtime/virtual entity definitions |
BareMetalWeb.API |
REST API controller layer |
BareMetalWeb.AI |
AI-assisted admin and entity designer tools (Microsoft.Extensions.AI) |
BareMetalWeb.Intelligence |
BitNet b1.58 ternary inference engine (zero-dependency, AOT-safe) |
BareMetalWeb.Intelligence.CLI |
Interactive REPL for testing the inference engine |
BareMetalWeb.CLI |
Native AOT metal command-line tool |
BareMetalWeb.Agent |
Node agent — self-registration, attestation, and runtime polling |
BareMetalWeb.BootstrapAgent |
Bootstrap agent — runtime download, verification, and process management |
BareMetalWeb.ControlPlane |
Telemetry streaming, heartbeats, and control-plane client |
BareMetalWeb.Benchmarks |
BenchmarkDotNet micro-benchmarks |
BareMetalWeb.*.Tests |
xUnit unit tests for each library |
BareMetalWeb.IntegrationTests |
End-to-end integration tests |
BareMetalWeb.PerformanceTests |
Performance benchmarking console app |
A cross-platform, native AOT-compiled command-line tool for managing BareMetalWeb instances. No .NET runtime required — download the single binary for your platform and go.
Pre-built binaries are available as GitHub Actions artifacts from the Build CLI Binaries workflow. Each platform has its own downloadable artifact:
| Platform | Artifact Name | Binary | Architecture |
|---|---|---|---|
| Windows x64 | metal-win-x64 |
metal-win-x64.exe |
Intel/AMD 64-bit |
| Windows ARM64 | metal-win-arm64 |
metal-win-arm64.exe |
ARM 64-bit (Surface Pro X, etc.) |
| Linux x64 | metal-linux-x64 |
metal-linux-x64 |
Intel/AMD 64-bit |
| Linux ARM64 | metal-linux-arm64 |
metal-linux-arm64 |
ARM 64-bit (Raspberry Pi 4+, AWS Graviton, Android/Termux) |
| All platforms | metal-all-platforms |
All of the above | Combined download |
To download: Go to Actions → Build CLI Binaries, click the latest successful run, and download the artifact for your platform from the bottom of the page.
On Linux, make the binary executable after download:
chmod +x metal-linux-x64Termux / Android (proot): The .NET runtime requires a GC heap limit in memory-constrained environments:
export DOTNET_GCHeapHardLimit=0x10000000
./metal-linux-arm64 help# 1. Connect to a BareMetalWeb instance (with API key)
metal connect https://mysite.azurewebsites.net my-api-key-here
# 2. Login via device code flow (opens browser, approve in browser)
metal connect https://mysite.azurewebsites.net
metal login
# 3. Login via device code (headless/SSH - shows code to enter manually)
metal login --outofband
# 4. Or login directly with credentials
metal login admin mypassword
# 5. Discover what entity types are available
metal types
# 4. List all records of a type
metal list to-do
# 5. Create a new record
metal create to-do Title="Buy milk" Notes="From the store" IsCompleted=false
# 6. Get a single record
metal get to-do abc123
# 7. Update a record
metal update to-do abc123 IsCompleted=true
# 8. Delete a record
metal delete to-do abc123| Command | Description |
|---|---|
metal connect <url> [api-key] |
Set the server URL and optional API key |
metal login |
Login via device code flow (opens browser for approval) |
metal login --outofband |
Login via device code (displays code for manual entry) |
metal login <user> <pass> |
Login directly with username/password |
metal config |
Show current connection configuration |
Authentication priority: API key (if configured) → Session cookie (from login).
Configuration is stored in ~/.metal/config.json. Session cookies are persisted in ~/.metal/cookies.
| Command | Description |
|---|---|
metal types |
List all entity types on the server (via /api/_meta) |
metal list <type> |
List all entities of a type |
metal get <type> <id> |
Get a single entity by ID (JSON output) |
metal create <type> key=value [...] |
Create a new entity |
metal update <type> <id> key=value [...] |
Partial update an entity (PATCH) |
metal delete <type> <id> |
Delete an entity |
# Full-text search
metal query to-do q=milk
# Filter by field with operator
metal query to-do field=Title op=contains value=milk
# Sort and paginate
metal query to-do sort=Deadline dir=desc skip=0 top=10
# Combine filters, sort, and pagination
metal query to-do field=IsCompleted op=eq value=false sort=Deadline dir=asc top=5Available operators: eq, ne, contains, startswith, endswith, in, notin, gt, lt, gte, lte
The CLI uses GET /api/_meta to discover entity types at runtime. This means one CLI binary works with any BareMetalWeb instance — it dynamically adapts to whatever entities are registered on that server. Different BareMetalWeb editions with different data objects all work with the same CLI.
The CLI is in BareMetalWeb.CLI/ and can be built locally:
# Standard build (requires .NET 10 SDK)
dotnet build BareMetalWeb.CLI
# Native AOT publish for your current platform
dotnet publish BareMetalWeb.CLI -c Release -p:PublishAot=true -p:PublishTrimmed=true
# Cross-compile for a specific target (Linux ARM64 example, requires cross toolchain)
dotnet publish BareMetalWeb.CLI -c Release --runtime linux-arm64 -p:PublishAot=true -p:PublishTrimmed=trueThe repository includes a helper script for running tests with minimal, scannable output:
# Run all tests with clean output (no build noise)
./run-tests.sh --no-build
# Run all tests (includes build)
./run-tests.sh
# Run specific test project
./run-tests.sh --no-build BareMetalWeb.Core.Tests/For more details, see TESTING.md.