/technology/ · How it is built

The engineering, in one place.

Cratefield is a managed service on top of Harness, an open-source Rust backend harness. This section is the technical half of the site: the request path, what a module is, every capability with the evidence behind it, and the row-by-row comparison with Supabase. None of it is required reading to use the product, and all of it is readable without an account.

MITRust, wasm3218 crates~32k lines384 testsclippy -D warningscargo denywasm build in CI#![forbid(unsafe_code)]

Four pages

Where the detail lives.

The composition

One file wires the whole backend.

This is the example venture in the repository, with the comments and the mailer's arguments trimmed to fit. Each .module() is a crate. Each .runtime() call supplies an adapter for a port. .ui() is what turns the modules into pages. Swap Resend for another mailer, or the hosted runtime for a native binary, and the modules do not change.

That is the whole composition. If a module needs a port the runtime doesn't provide, this doesn't compile.

examples/venture/src/lib.rs · SHIPPING
Harness::builder()
    .venture(Venture::new(
        "venture-example", "example.factory0.dev")
        .public_url("https://example.factory0.dev")
        .cors_origins(["https://example.factory0.dev"]))
    .module(EmailSignup::new())
    .module(Waitlist::new()
        .products(["kontinuum", "undercover-rockstars"])
        .confirm_ttl_days(7))
    .templates(templates)
    .ui(Ui::from_spec(include_str!("../ui.json"))?)
    .runtime(Cloudflare::new()
        .db("DB")
        .mailer(Resend::new(..)))
    .build()?

The shape of it

Modules in. One binary out. A database each.

01  You pickcrates

email-signupshipping
waitlistshipping
authdesigned
secretsdesigned
your owna crate

02  We compilebuild time

Harness::builder()
  .module(…)
  .runtime(…)
  .build()?
A missing port, two modules on one table, a contract mismatch — none of it compiles.
acme_backend.wasm

03  You runone db each

acmeisolated
northwindisolated
globexisolated
tenant Nisolated
no shared tablesno RLS

The same picture is the argument. What you assemble is crates, so the checks happen in cargo test rather than in production. What comes out is one binary, so there is nothing to configure at runtime. What runs is one database per backend, so a mistake cannot reach the backend next door. Per-customer databases inside one product are Designed, in epic #23. The request path, in detail.

The argument, technically

A backend you compile, not a platform you configure.

01

Modules are crates, composed at compile time.

A backend lists module crates in Cargo.toml and wires them in one file. The binary contains exactly those modules. Harness::build() refuses a module that needs a port the runtime doesn't provide, two modules claiming the same route prefix or table, or a module built against a different contract version. Misconfiguration fails cargo test, not production.

02

Portability is architectural, not a promise.

Modules never touch a vendor client, a platform binding or an environment variable. They receive trait objects and adapters answer. CI builds the example backend to wasm32 every commit: a dependency pulling tokio, mio or std::fs fails the build. MIT, not BSL.

03

Stateless by construction, at the edge.

Rust compiled to WebAssembly and served at the edge. No static mut, no thread-local outliving a request, no session store. Request scope travels in axum extensions, and the conformance kit ships the concurrent-request test that proves it.

Changing modules is a deploy.

Toggling a module regenerates Cargo.toml and harness.rs, rebuilds Rust to wasm and redeploys. Tens of seconds to minutes, with a build log. There is no instant config flip, and we won't draw one.

What this does not do

The limits, as numbers.

Read these before the comparison. Full version on the comparison page.

  • The database is SQLite, not Postgres. No pgvector, no extensions, no LISTEN/NOTIFY. 10 GB per database, a hard cap the provider does not raise. Single-threaded: throughput tracks query duration, roughly 1,000 queries/sec at 1 ms, about 10/sec at 100 ms.
  • No realtime and no object storage. There is no general data browser either. The admin UI renders each module's own admin views over its own tables, which is not the same thing as a console onto the database.
  • The control plane does not exist yet. Not a line of it. Early access is early access.
  • What to do about it. Run it on Postgres instead. The Postgres adapter and the native tokio runtime are merged, CI tests every module against both engines, and fz data export moves a venture's rows from D1 into Postgres. The 10 GB cap and the single-threaded write path are D1's, not the harness's.

The code is the documentation you cannot be talked out of.