Engineering
Running your code — safely, at native speed: why FastYoke chose WebAssembly
FastYoke Engineering · 10 min read · May 9, 2026
- WebAssembly
- Multi-tenancy
- Security
- Sovereignty
Every tenant runs code we didn't write
FastYoke is a platform for building operational software — workflows, decision logic, forms, scripts. The whole point is that you define how your business runs: the guard that decides when a job can advance, the rule that prices an order, the script that reshapes a payload. That logic is authored by our customers, and there are a lot of them.
So on any given server we are executing code we did not write, from many different organizations, side by side. And increasingly that server isn't even ours: the same engine runs in our cloud, inside a customer's own data center, on a gateway at the edge, and in air-gapped installations.
That is a genuinely hard problem. Running untrusted-but-yours logic, from thousands of tenants, on infrastructure we don't always control, without letting any of it read another tenant's data, exhaust the machine, or reach out to the network. This post is about the tool we reached for to solve it — WebAssembly — and the specific decisions that turn it into a security and sovereignty guarantee rather than just a buzzword.
Why the obvious answers don't work
There are two classic ways to run other people's code, and both fail for a multi-tenant platform.
A container or subprocess per tenant. Strong isolation, but you pay for it: cold-start latency on every evaluation, an operational surface that balloons with tenant count, and a resource floor that makes "evaluate one small guard" absurdly expensive. It does not scale to thousands of tenants each firing logic thousands of times a day.
A raw in-process interpreter. Fast to start and cheap per call — but you are now trusting an interpreter with your entire host process. A bug or a hostile input is a path straight into everything the server can touch. And for compute-heavy logic, interpreters are slow.
We wanted the isolation of the first option with the speed and density of the second. That combination is exactly what a modern WebAssembly runtime provides.
The choice: a compiled, capability-secure sandbox
We run tenant logic inside wasmtime, a
production WebAssembly runtime built by the
Bytecode Alliance, in-process. Where tenants want to write
plain TypeScript rather than hand-authored modules, we compile a
JavaScript engine (QuickJS) to WebAssembly and run that inside the same
sandbox — so ordinary scripts inherit every guarantee below.
WebAssembly gives us three properties that matter here: it is compiled (near-native execution, not interpreted line by line), it is memory-safe (a module cannot reach outside its own linear memory), and it is capability-based (a module can do exactly nothing to the outside world unless we explicitly hand it the ability). The rest of this post is the set of decisions we made on top of those properties.
Decision 1 — a fresh sandbox for every single call
Each evaluation gets a brand-new instance. We build a fresh execution context per call and throw it away afterward; nothing carries over from one evaluation to the next. There is no shared mutable state for one tenant's logic to stash something in and another tenant's logic to find.
Decision 2 — bounded resources, so no one can take the node down
A sandbox that can loop forever or allocate without limit is still a denial-of-service waiting to happen. So every call runs under two ceilings:
- A fuel budget — the runtime meters execution and stops a module that burns through its allotment. Guards are meant to be millisecond-scale; blowing the budget means an infinite loop, and we cut it off instead of letting it wedge the machine.
- A hard memory ceiling — a module cannot grow its memory past a fixed cap. Runaway allocation fails safely instead of starving everything else on the box.
The effect is that a buggy — or hostile — piece of tenant logic can fail, but it cannot spread. Your neighbors' workloads, and the node itself, keep their latency budget.
Decision 3 — Border Control: no network, no filesystem, no syscalls
This is the decision we care about most, and the one that turns "we run your code" into "we run your code without letting it leak anything."
The sandbox is built with no inherited network sockets. The runtime's I/O context is constructed without access to TCP or UDP — those capabilities are simply never handed to the module. There is no ambient filesystem, no host syscalls, no way to open a connection. If tenant logic needs to cause an effect in the outside world, it must ask through one narrow, explicitly-defined surface that we mediate and gate.
Capability-based security means the default is nothing. That is a much stronger position than "sandbox and hope the deny-list is complete."
Decision 4 — determinism and content addressing
We turn off the nondeterministic corners of the runtime: the same module, given the same input, always produces the same output. On top of that, every module is identified by a cryptographic hash of its bytes and compiled once, then cached.
Two things fall out of this:
- Auditability. Because a module is pinned by its hash and runs deterministically, an evaluation is reproducible and replayable. You can prove exactly which logic ran and what it did.
- Speed. Compilation is the expensive step, and we pay it once per distinct module; every subsequent call reuses the compiled artifact. After warm-up, you get native-class throughput with none of the per-call container overhead.
What those decisions buy you
Step back, and the engineering choices add up to three things a buyer actually cares about.
Performance
Near-native execution, no per-tenant container cold starts, compiled modules cached and reused, and a fuel budget that keeps tail latency predictable. Dense multi-tenant execution without a fleet of sidecars.
Multi-tenant security
Isolation (a fresh sandbox per call) plus bounded resources (fuel and memory caps) plus zero ambient authority (no network, no filesystem) means one tenant's logic cannot read another tenant's data, cannot exhaust the machine, and cannot escape the sandbox. Not by policy — by construction.
Data and IP sovereignty
The same sandbox runs identically in our cloud, inside your own data center, on an edge gateway, or fully air-gapped. Your logic and your data never have to leave your deployment; the runtime can't call out even if something tried to make it. And because every module is content-addressed and auditable, the intellectual property you encode as logic — your pricing rules, your models, your workflows — runs where you keep it, and you can prove what ran.
That last point is the one we keep coming back to. WebAssembly didn't just let us run customer code cheaply. It let us make a promise we can actually keep: your code, and your data, stay yours — wherever FastYoke runs.
Want the deployment side of this story? See On-Prem and FastYoke Substrate, or open your Trust Center.