/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 comparisons — Supabase, Firebase, InsForge and hosted Postgres. None of it is required reading to use the product, and all of it is readable without an account.

MITRust, wasm3265 crates~397k lines3,381 testsclippy -D warningscargo denywasm build in CI#![forbid(unsafe_code)]

Seven 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 would regenerate Cargo.toml and harness.rs and deploy a new backend, with a build log. The artifact would be keyed on the module set, so a compile would happen only for a module set that has not been built before (#59); when one does, it takes seconds (measured). 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.
  • Realtime does not run at the edge yet. The Realtime port and its in-process adapter are merged and run on the native runtime; the Cloudflare Durable Object adapter behind the same port is specified and unbuilt (#103). Object storage does ship, as a Blob port over R2 or a directory (#105).
  • There is no general data browser. 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 is not running. It is being built in the open in Cratefield/harness, and it is not available. 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.