Ryft: Compiling App-Scoped Backends Into Native Services
By Raymund Zyron Abella /
Declared apps, strict JSON codecs, local dependency locks, and native compilation make backend boundaries inspectable in the Ryft developer preview.
In this article
Ryft starts with a specific backend shape: several applications share a deployment, but each application has its own routes, helpers, storage declarations, and resource budgets. The language makes those boundaries part of the source instead of leaving every project to recreate them through conventions.
The current implementation is a statically typed language written in Rust. Checked .rz programs become generated Rust and compile through a locked Cargo backend into native executables. The source folder is named Forge; the current product is Ryft 0.3 developer preview.
The Ryft project page includes the Windows compiler bundle, editor extension, screenshots, and an implementation excerpt. This article focuses on what the language checks and which runtime guarantees remain limited.
Begin With an App Boundary
A small program can declare a shop application and a chat application, assign different base paths, and define separate request budgets. Routes live inside their owning app. Storage handles and private helpers can therefore have a meaningful application scope.
That is more useful than a decorative namespace. A helper intended for one app should not become an unrestricted cross-app entry point. A declared environment capability tells the runtime which configuration names the program expects instead of opening every host setting implicitly.
For a first experiment, inspect the multi-app example on the project page, then change a route's declared return type or attempt an invalid reference. The interesting result is the diagnostic before deployment, not merely whether the happy-path endpoint returns JSON.
Static Types Reach the JSON Boundary
Ryft supports structs, enums, exhaustive matching, Result/Option, typed collections, methods, and inferred generic functions. These features help make a request's accepted shape explicit before domain code uses it.
Struct codecs reject unknown fields, missing fields, and invalid types. Optional fields must still appear with a value or null. That is a deliberate contract: an absent field and an explicitly nullable field are not silently interchangeable.
Enums encode their alternatives, while exhaustive match makes callers handle the permitted cases. Parsing an integer or JSON can return a Result rather than pretending malformed input has a valid default meaning. Collection lookups can return Option instead of an unchecked value.
These constraints also create boundaries around what the language currently offers. Generic function arguments are inferred, but user-defined generic structs and trait constraints are not implemented. Methods work with owned values; borrowed in-place mutation is not part of this method model.
What Native Compilation Changes
The compiler checks the source, generates Rust, and invokes its locked backend toolchain. The result can run without shipping the Ryft compiler and source tree alongside the service. Building still requires Rust and the appropriate native C++ tooling on the build machine.
Generated code is part of the debugging story too. The emit-Rust option provides an inspectable artifact when an issue crosses the source-to-runtime boundary. It does not replace a source-level debugger, which this release does not supply.
Native output also does not make arbitrary application code safe. The usefulness of compilation depends on the checks, storage contracts, capability boundaries, and runtime guards that surround it. A deployable executable is an artifact, not a production-readiness certificate.
Modules and Locks Make Projects Inspectable
Aliased imports expose public functions, structs, enums, methods, and re-exports. Private module state stays outside that exported surface. The older unaliased import form retains shared-namespace behavior for compatibility, so those two forms should not be assumed equivalent.
Project manifests name an entry and local path dependencies. A lock records dependency content hashes; subsequent checks and builds reject changes until that lock is refreshed. This is a local dependency workflow, not an implemented remote package registry.
The distinction matters when sharing an example. Someone should be able to tell which source was checked and whether a local dependency changed underneath it. The lock gives that question an explicit answer rather than relying only on a directory name.
Request Budgets Have Specific Meanings
The runtime includes admission controls, body limits, deadlines, bounded query results, and cooperative guards. A connections budget limits active requests, not every underlying TCP connection. An HTTP deadline does not forcibly cancel every synchronous database operation.
The default mode runs apps in one process. Optional Windows isolation launches a worker per app and uses Job Objects for configured memory and CPU controls, with crash detection and restart backoff. A single deployment binary can launch those workers itself.
This is narrower than a hardened universal sandbox. Filesystem isolation and Windows Server qualification remain open work. The article therefore treats the budgets as implemented controls with documented meanings, not a promise that any untrusted program can be hosted securely.
Storage and Lifecycle Are Part of the Language
Apps can declare SQLite or MongoDB handles and use bounded operations. SQLite transactions commit a batch or roll it back. MongoDB transaction results can expose uncertain commit outcomes that require reconciliation rather than blindly replaying an entire operation.
Startup and shutdown hooks make service lifecycle explicit. Startup runs after storage initialization and before readiness. Shutdown follows graceful draining, but cannot run after every crash or forced termination. Request-only APIs are not available inside those hooks, including through helper calls.
Those distinctions matter to user-facing reliability. An application should not report readiness before its required storage is ready, or depend on a graceful shutdown hook as its only way to preserve important data.
Fieldwork Tests the Integration Boundary
Fieldwork uses Ryft for strict project/task validation, Zyra for its interface, and ZeeDB for persistence. Ryft 0.3 has no native ZeeDB driver or outbound HTTP capability, so a small Node adapter calls the validation service and writes through the ZeeDB API.
That explicit adapter is useful evidence about the current language. It shows where the abstraction works and where another component is required. It avoids presenting an application integration as a built-in driver that does not exist.
Explore the Current Preview
The project downloads and guide include the supplied compiler and VSIX. Editor support covers diagnostics, navigation, references, checked rename, signature help, and formatting, with the documented limitations of the preview.
Try checking a small app, changing an input codec, and following a rejected program back to its source location. For evaluation, I would observe diagnostic clarity, incorrect assumptions about budgets, and whether developers can identify an uncertain database outcome. No comparative throughput or production-deployment result is claimed here.
For the other language directions, read Ze's multilingual interpreter and Zy's automation runtime. Zyra's article covers the frontend framework used in Fieldwork.