Architecture
How Dynamic Apps serves, builds, and stores user-generated applications.
Dynamic Apps is a library, not a hosted app deployment platform. You own the routing server, its authentication, and the URL on which applications are mounted.
The request lifecycle looks like:
- Your routing server receives a request.
- Your middleware handles it: authentication, rate limits, whatever else you run.
- The request is passed to
appsRouter. appsRouterexecutes it in the agentOS VM for that app, starting the VM if it isn’t already running.
import { serve } from "@hono/node-server";
import { appsRouter } from "@rivet-dev/dynamic-apps";
import { Hono } from "hono";
const server = new Hono();
// This is how the Rivet control plane communicates with your backend.
server.all("/api/rivet/*", (c) => appsRouter.fetch(c.req.raw));
// Mount every deployed application at /apps/:appId.
server.route("/apps", appsRouter);
// Serve the host router over HTTP.
serve({
fetch: server.fetch,
port: 3000,
});
Requests reach your routing server, where appsRouter executes them in a
cached agentOS VM embedded in the same process. There is no network hop to
another service, and warm requests never touch storage. Apps export fetch
handlers; Dynamic Apps owns any listener inside the VM.
Deployment is separate from serving
deployApp() builds the files in a sandboxed agentOS build VM and publishes an
immutable release. The default @rivet-dev/dynamic-apps package stores
releases in Rivet. @rivet-dev/dynamic-apps-core lets you
supply another store.
App-defined actors
An app may also export a RivetKit registry. Those app-defined actors use normal Rivet routing for durable state, actions, events, and connections. Dynamic Apps imports the app once into a cached server process, then sends both ordinary HTTP and Rivet callbacks through that process.
agentOS provides the filesystem, process, environment, and network permission boundary for direct requests and app-defined actor workers.