Running Untrusted Partner Code on Shopify’s Own Infrastructure

Shopify’s App ecosystem relies on independently hosted web services that talk to the platform over the network. While that model is flexible, it pushes a lot of operational burden onto Partners and adds network latency that makes some use cases—like synchronous cart or checkout customizations—impractical. Shopify’s answer is to keep the flexibility of untrusted Partner code but run it on Shopify’s own infrastructure, using WebAssembly (Wasm) as the execution format.

Wasm is a binary instruction format for a stack-based virtual machine, designed as a portable compilation target. Shopify runs Wasm outside the browser, with no JavaScript involved. The company’s requirements for this code execution service map cleanly onto Wasm’s core properties: security, performance, and flexibility.

Why WebAssembly Fits

Executing untrusted code is inherently dangerous. Wasm mitigates this by running inside a sandboxed, stack-based environment. Communication with the host happens only through explicit imports, which means you cannot express malicious operations in Wasm—only manipulations of the virtual environment using provided imports. The format also includes protections against buggy code, such as protected call stacks and runtime type checking.

Performance was another deciding factor. Ecommerce speed directly affects sales, and any customization feature has to come with a reasonable load-time tradeoff. Wasm is built to leverage common hardware capabilities for near-native performance, and its tooling ecosystem has been optimized with performance as a primary goal.

Flexibility matters too. Wasm is a bytecode format targeted by multiple compilers, which means Shopify can support several programming languages without changing the underlying execution model. The company also emphasizes the health of the Wasm community itself: an active ecosystem that is constantly building new tools and closing feature gaps is essential for long-term adoption. Shopify has been feeding back into that community through open source contributions and user feedback.

Runtime Architecture and Lucet

Shopify executes Wasm modules using Lucet, an open source tool originally written by Fastly. Fastly’s problem—running high-volume, short-lived, untrusted modules at the edge—closely mirrors Shopify’s needs, so the tool was a natural fit.

Lucet is both a runtime and a compiler. Modules stay in Wasm form for safety, pass a validation step, and then compile to executable artifacts with near bare metal performance. It supports ahead-of-time compilation, so Shopify can have artifacts ready before a request arrives. Lucet containers reach startup times around 35 μs, since there is no per-invocation setup work needed.

A flow diagram showing how Shopify uses our Wasm engine: Lucet wrapped within a Rust web service which manages the I/O and storage of modules
A flow diagram showing Shopify's Wasm engine

Shopify wraps Lucet in a Rust web service called the Wasm Engine, which handles module I/O and storage. The engine is called during runtime processes—typically web requests—to satisfy a function that needs synchronous behavior, such as creating a discount or enforcing a constraint.

Measured Execution Overhead

In a recent performance test, 100k modules per minute ran for about five minutes. Each module enforced a trivial limit on items purchased in a cart. The p99 execution time inside Lucet hovered around 100 μs. Once I/O and engine overhead were included, total module execution came in around 4 ms.

A line graph showcasing the time taken to execute a module. The x axis representing the time over the test was running and the y axis is the time represented in ms
Time taken to execute a module

By comparison, the p99 request time for Shopify’s Storefront Renderer—the performant online store service—is around 700 ms. Module execution under 5 ms is therefore negligible in the context of a full request lifecycle.

A line graph showing Storefront Renderer Response time
Storefront Renderer response time

Choosing AssemblyScript as the Partner Language

Not every language with a Wasm target is practical for partners to use. Shopify wanted first-class support for a single language with good tooling, so developers could focus on solving merchant problems rather than conforming to an unfamiliar API.

Ruby, Shopify’s internal language of choice, is dynamic and cannot be compiled directly to Wasm. Compiling interpreters for dynamic languages came with a steep performance penalty. JavaScript was also ruled out for the same reason. The team chose AssemblyScript, which offers TypeScript-like syntax and compiles to a narrow, self-contained Wasm module.

Many Wasm compilers are unsuitable for this use case because they generate artifacts tied to specific environments like Node or the browser, or they produce modules that depend on special language-specific runtime imports. AssemblyScript targets plain Wasm, which is what Shopify needs: tools that produce Wasm, not tools that are powered by Wasm.

AssemblyScript is still under active development and has gaps, including missing closure support and some edge case bugs. Shopify has acknowledged this tradeoff and invested in the community through an OpenCollective donation, code contributions, and a language server. Shopify has also worked toward implementing closures and fixed compiler bugs.

On the tooling side, Shopify has integrated AssemblyScript into the Shopify CLI, enabling developers to create, test, and deploy modules from the command line. SDKs abstract low-level implementation details for Shopify objects like Money, and systems are being built so partners can monitor module behavior and receive failure alerts—preserving the observability they would get from hosting code themselves.

Beyond the Browser

Shopify’s adoption of WebAssembly is fundamentally about expanding what third-party code can do inside its platform. The company has moved past the browser entirely, using Wasm as a sandboxing and portability layer for untrusted merchant and partner code running on Shopify’s servers. The result is a system where custom logic executes safely, with predictable performance, across a diverse range of tenants.

The core driver is the Scripts team, which builds and manages the infrastructure for this kind of embedded execution. Their work focuses on a few key properties: strict isolation, consistent runtime behavior, and the ability to accept code written in multiple languages without forcing merchants to adopt a specific toolchain.

Why Wasm Wins on the Server Side

Historically, running untrusted code at scale meant either heavyweight containerization or restrictive DSLs. Both approaches carry tradeoffs. Full OS-level containers impose significant overhead per request and complicate scheduling, while restrictive domain-specific languages limit expressiveness and push merchants toward writing logic that is hard to test or port.

WebAssembly offers a middle path. It provides a compact binary format with a formal specification, memory safety guarantees, and deterministic execution boundaries. Because the module system is language-agnostic on the client side, Shopify can accept compiled Wasm from any source language that has a target. On the serving side, the runtime is lightweight enough to spin up alongside a request without the operational cost of a container pool.

Another factor is the portability of the compiled artifact. Instead of distributing source code and building it in Shopify’s environment, merchants compile locally and upload a single wasm binary. That binary is both the deployment unit and the sandbox boundary, which simplifies versioning and rollback procedures.

Performance characteristics also matter in latency-sensitive checkout contexts. Wasm’s JIT and baseline compiler tiers let Shopify run custom logic at near-native speed, which makes it viable for operations previously handled only by server-side Ruby or Go code.

The Runtime and Its Boundaries

Under the hood, Shopify pairs the compiled module with a constrained runtime environment that provides only the imports a scripted application could need. This reliance on an explicit import table is central to security: the module cannot touch host filesystem, network sockets, or process memory unless the runtime deliberately exposes those capabilities as imported functions.

Memory is managed within the module’s own linear memory space, isolating faulty or malicious code from the host process. The WebAssembly specification’s type system is also enforced at validation time, so any module that attempts to violate its declared types is rejected before execution ever starts.

They pair this with a set of policies around CPU and memory exhaustion. Execution is time-boxed, which guards against non-terminating loops. That allows Shopify to treat custom logic as a bounded resource call rather than a potential denial-of-service vector. All of this means wasm32 binaries serve as the common runtime for business logic, irrespective of whether the originating language is Rust, C, or other Wasm-capable stacks.

Creating New Opportunities for Extensibility

The architectural work here is not just about isolating hostile code. It’s about building abstraction layers that support a growing set of capabilities. The platform team points to the blurring of Partner and Merchant boundaries as a direct outcome of this shift. With programmatically verifiable code instead of opaque text, third-party solutions can behave more like native platform features, while operators retain fine-grained control over which shipped code executes.

Current work is centered on increasing the library of standard functions that scripts can import from the runtime, so that more merchant requests can be fulfilled without needing bespoke changes to the hosting core. That creates a feedback loop around developer experience: easier extension points mean more partner solutions, which highlight other features worth exposing to the Wasm module system.

The whole setup dramatically lowers the barrier required to implement plugin-like architectures within Shopify. Each deployed module represents a precise slice of business logic—inventory adjustments, pricing rules, or shipping calculations—packaged and executed independently of the monolith’s release cadence. That separation provides a path toward more granular independent deployability and helps de-risk the surface area of the platform.

Experimental Prototyping in Public

This approach underlies continuous experiments, including rethinking how to make commerce applications exchange code and data with fewer rigid segments. For third-party developers, the practical entry point remains straightforward: develop against a defined API surface, compile to Wasm, and upload the artifact into an environment with clear behavioral constraints.

The WebAssembly focus is part of the Shopify engineering organization’s broader open source culture. Developers experienced with performance-sensitive plugin systems, API design, and new language targets will find familiar terrain here. Shopify’s teams openly embrace remote and collaborative workflows, while the engineering blog continues to be a hub for deep dives into that kind of extensibility frameworks.

As broader ecosystems accelerate Wasm adoption beyond browser contexts—in edge computing and serverless execution, for instance—efforts such as Ruvy and other tooling demonstrate that Shopify intends to stay ahead of that curve. Whether in pricing, shipping, or future logical modules, the infrastructure work already done provides a stable foundation for whatever novel capabilities that ecosystem unlock next.