Portable business logic across browser, server, and edge
How to write a pricing rule, validation check, or eligibility formula once and run it identically everywhere without copy-paste.
The problem: logic drift across environments
Most non-trivial products apply the same business rules in more than one place. A pricing formula runs on the server when generating an invoice, in the browser when showing a live total, and at the CDN edge when personalizing a landing page. A validation rule runs in a form input handler, in an API endpoint, and in a background job that reprocesses historical records.
When those rules live in the same codebase, they start identical. After a few months they do not. The backend version gains a special case for a new product category. The browser version keeps an old rounding behavior because the team forgot to update it. The edge version is a rough approximation written in a different language by a different team under time pressure. At some point, the three versions agree on most inputs and silently disagree on the rest.
That divergence is not a discipline failure. It is what happens when the same logic is owned by different layers, tested in different pipelines, and deployed on different release cadences.
Why it keeps happening
The standard response to this problem is a shared library. Extract the rule into a package, import it everywhere, and update one place. In a single-language monorepo, this works reasonably well. In a real production system, it fails in predictable ways.
The browser cannot import a Node.js module with database access patterns baked in. The edge function runtime does not support the same standard library as the server. The AI agent calling the rule at inference time needs a stateless, sandboxed invocation with no ambient I/O. Each environment has different constraints, and a shared library written for one environment tends to accumulate assumptions that make it unusable in the others.
The result is that teams maintain separate implementations. The implementations start aligned and drift over time. Drift is discovered late, usually in production, usually after the business has already made decisions based on inconsistent outputs.
How Universal Microservices Architecture (UMA) solves it
A UMA portable service packages business logic as a WebAssembly module paired with an active descriptor. The WASM module contains the compiled logic. The descriptor declares what the module expects as input, what it produces as output, and what capabilities it requires from the host. The module has no ambient I/O access by default. It cannot open sockets, read files, or touch environment variables unless the host explicitly grants those capabilities at startup.
Because the module targets the WASM binary format, not a specific language runtime or OS, the same artifact runs in a browser via the native WebAssembly API, in a Cloudflare Worker or Fastly Compute instance at the edge, in a wasmtime process on a server, and inside an AI agent tool invocation. The execution semantics are defined by the WASM specification. The behavior is deterministic across all four targets from the same binary.
The active descriptor is what makes the service governable rather than just portable. It carries the typed interface contract, versioning information, and the capability surface. A runtime can inspect the descriptor before executing to verify that its environment satisfies what the module needs. This moves compatibility checks from runtime surprises to load-time validation.
Ownership of the rule stays with one team. That team ships one artifact. Every environment runs that artifact. When the rule changes, every environment gets the updated behavior on the next deployment without coordination across teams.
Concrete example: a pricing rule across three targets
Consider a pricing rule that applies volume discounts, promotional codes, and region-specific tax rates. The rule takes a cart snapshot and a customer context object as inputs and returns a priced total with a breakdown of applied adjustments.
Written as a UMA portable service:
- In the browser. The WASM module is loaded once at page load. The pricing rule runs locally on every cart update with no round trip. The customer sees accurate totals while editing quantity fields, applying promo codes, or switching shipping regions. The module works offline. It does not call the server for every recalculation.
- On the server. The same module runs inside the order processing service at checkout. The server hosts a wasmtime runtime, loads the module from the service registry, and invokes it with the final cart state before writing the order record. The output is bit-for-bit identical to what the browser showed the customer, because both ran the same module.
- At the CDN edge. The same module runs inside a Cloudflare Worker to personalize pricing previews on category pages for logged-in users. The edge worker fetches the module from the registry, instantiates it with the customer's regional context, and renders the adjusted price directly in the response. No origin request is needed for the pricing calculation.
When the finance team adds a new discount tier in January, the team that owns the pricing service ships one updated WASM artifact. The browser, the server, and the edge all pick up the change on their next module load. There is no cross-team coordination. There is no risk that the browser version misses the update because it lives in a different repository.
Where to go next
Portable business logic is one application of the broader UMA model. The approach works because the core model separates what a service does from where it runs, and because WASM provides an execution boundary that holds across environments without recompilation.
Go deeper
- The UMA core model — how active descriptors and portable services fit together as an architecture.
- WASM microservices — the execution model that makes environment-agnostic deployment possible.
- How UMA works — end-to-end walkthrough of the runtime, registry, and governance layer.
- Pre-order on Amazon — the full treatment of portable service design, with worked examples in Rust and TypeScript.