Skip to main content
Concepts

Deploying Apps

Deploy a directory or generated files with deployApp(), preserve rollback, and configure app actors.

Deploy a local application directory:

await deployApp({
  appId: "hello-world",
  source: new URL("../fixtures/app/", import.meta.url),
});

Or pass a complete generated application tree:

await deployApp({
  appId: "generated-app",
  files: {
    "package.json": JSON.stringify({
      private: true,
      type: "module",
      main: "index.js",
    }),
    "index.js": `
      export default {
        fetch() {
          return new Response("hello");
        },
      };
    `,
  },
});

The direct entrypoint must default-export a function or an object with fetch(request). Code runs inside agentOS with filesystem, process, environment, and network permissions, and supported Node builtins are available. Directories that contain only static files are rejected; see Static Websites. Native addons are not supported.

Build repair and rollback

deployApp() rejects with bounded build diagnostics when generated source does not compile. Feed those diagnostics back to the generator and try again:

for (let attempt = 0; attempt < 3; attempt++) {
  try {
    await deployApp({ appId: "generated-app", files });
    break;
  } catch (error) {
    if (attempt === 2) throw error;
    files = await repairWithAgent(files, String(error));
  }
}

Include webServerSkill and rivetActorsSkill from @rivet-dev/dynamic-apps in the model prompt. They describe the supported TypeScript server layout and Rivet actor integration. View the complete AI App Builder example.

A failed build or incomplete artifact write never replaces the active release. A successful call returns only after the immutable artifact is persisted and activated; it does not mean a request-serving replica was warmed.

With core, this is the publishRelease guarantee: make the complete artifact durable first, atomically replace the active release second, and resolve only when loadActiveRelease can read it. The default adapter provides those semantics through its per-app Rivet actor.

appId must contain 1–63 lowercase letters, numbers, or hyphens. Pass exactly one of source or files.

Configuration

await deployApp({
  appId: "my-app",
  source,
  regions: ["atl", "fra"],
  scaling: {
    minReplicas: 0,
    maxReplicas: 128,
    targetConcurrency: 8,
  },
});
OptionDefaultMeaning
regionsState actor’s current regionStored compatibility metadata; it does not move direct HTTP execution
createNamespacenoneDeprecated compatibility option; every app always receives its own stable namespace
scaling.minReplicas0App-defined actor runner setting; compatibility metadata for direct HTTP
scaling.maxReplicas128App-defined actor runner setting; compatibility metadata for direct HTTP
scaling.targetConcurrency8App-defined actor runner setting; compatibility metadata for direct HTTP

Every app receives its own Rivet namespace. Locally, configure an Engine secret token with permission to create namespaces. On Rivet Cloud, set RIVET_CLOUD_TOKEN to a cloud_api_* token for the project; deployApp() uses it to create the namespace and namespace-scoped actor credentials. Keep this management token server-side. The deployment result includes the app’s Engine endpoint, namespace, pool, and publishable token for connecting to app-defined actors.

Rivet Compute automatically uses the deployment’s .rivet.run/api/rivet callback. For another public host, set DYNAMIC_APPS_CALLBACK_URL to its origin.