ObjectStackObjectStack

Deployment Overview

Two things deploy on this platform and they move on separate clocks — the platform runtime you operate, and the metadata app you build. Which one you are doing decides which pages in this section are yours.

Two different things get deployed here, and they run on separate clocks:

The platform runtimeYour metadata app
The sentence that fits"I operate ObjectStack.""I build an app that runs on it."
Ships asa Docker image (or the os CLI on a host)a compiled artifact, dist/objectstack.json
Versioned byour release train (X.Y.Z)your own catalog
Whose cadenceoursyours
The deploy actionmove the image tag, restartcompile, then install it or pin it at boot
Rolling backrestore the previous tag or artifactinstall the previous version

The two are genuinely independent: a deployment can move from platform 16 to 17 without touching its app, and publish twelve app versions without moving the platform. Most deployment questions are really the question which of these am I doing — so this section is ordered that way, and so is the sidebar.

Where it runs — Docker, Compose, Kubernetes, a bare Node.js host, or an ObjectStack Cloud environment — is a detail inside the first of those two, not a third thing alongside them. Pick which job you are doing first; the venue is a choice you make inside it.

Doing both is normal; doing both in one motion is not. A team that self-hosts its own app operates the runtime and ships the app — still two jobs, two cadences, two checklists. Read the one you are acting on today.


The platform runtime — you operate it

The platform ships as a single version-locked train: every @objectstack/* package shares one version number, and that number is the platform version. It is published as an official runtime image, ghcr.io/objectstack-ai/objectstack, whose tags mirror @objectstack/cli versions: the exact X.Y.Z, plus the rolling X.Y, X and latest tags. Pin the exact version in production and move it deliberately.

Where it runs

  • Docker — the standard path. The image is Node 22 + @objectstack/cli + os start, running as a non-root user with a built-in health check. Compose with Postgres and Kubernetes are shapes of that same path rather than alternatives to it; bare Node.js under systemd is the minority path, for hosts where a container runtime is not available. See Docker (official image).
  • ObjectStack Cloud. The control plane provisions environments and operates the runtime for you, and apps arrive by installing a package version from your organization's catalog. Cloud hosts, database provisioning, billing, and public SaaS distribution live outside this repository; the framework runtime exposes the environment registry, marketplace proxy, and runtime-config seams that distribution consumes.
  • A local runtime, for development. pnpm dev in this repository, or os dev in a generated app: one process, one active environment, no control-plane hop. See Single-Environment Mode.

How many environments one runtime serves

A single-environment host owns exactly one active environment, selected with OS_ENVIRONMENT_ID. An environment-aware host resolves one per request — from the scoped URL, the hostname, X-Environment-Id, the session, or a configured default. That is a property of the runtime you operate, not of the app it runs; the full precedence list is Resolution order. Control-plane endpoints under /api/v1/cloud/... manage environments rather than running inside one and are deliberately excluded from it.

The pages for operating the platform

PageWhat it answers
Self-Hosted DeploymentRunning the artifact on infrastructure you operate — Docker, Compose with Postgres, Kubernetes, systemd, health checks, reverse proxy and TLS, and the four values every deployment must pin
Production ReadinessSecurity headers, rate limiting, observability, and the go-live checklist
Backup & RestoreWhat state a deployment actually holds, how to back up each piece per database driver, and the restore drill to rehearse before you need it
Tenancy Postures & MembershipWhich of the three postures this deployment runs in, how new users join an organization, and the degraded-tenancy boot guard
Single-Environment ModeThe one-environment boot shape — what it includes, and what it deliberately does not

Upgrading the platform

Moving the platform forward is its own procedure: move the tag, restart, and know what the boot does when the database is still shaped for the previous version. See Upgrading → The platform runtime.


Your metadata app — you build it

An app is not part of the platform. It compiles to its own immutable artifact, carries its own version, and is released by you, when you decide:

objectstack.config.ts ──(os compile)──▶ dist/objectstack.json

Deployment config stays outside that artifact. Database URLs, auth secrets, runtime credentials, and environment identity are host inputs, injected as OS_* variables or CLI flags.

Validate before you compile

ObjectStack metadata is data, not code paths, so most mistakes pass tsc and then fail silently at runtime. One command catches them at author time:

os validate     # schema + CEL predicates + widget bindings — no artifact

Run it after every metadata edit — see Validating Metadata.

How the app reaches a running platform

There are two ways in, and picking the wrong one is the expensive mistake:

Catalog installArtifact-pinned boot
The app arrivesafter the platform is runningat boot, as an input to the process
Named bypackage id + version (com.acme.crm@1.2.0)a URL to the compiled artifact (OS_ARTIFACT_URL)
Switching versionsinstall another version; no restartchange the variable, restart
Apps per runtimemany, side by sideone — it is this runtime's app

One question decides it: is this app the reason the runtime exists? If yes, pin the artifact — the deployment defines the app. If no, install from the catalog — the runtime is a platform that receives apps. The full comparison, the tie-breakers, and every publish command are on Publish, Versioning & Preview; the operational detail of the pinned path is Artifact-pinned boot.

Publishing and installing are separate steps. os package publish uploads a versioned package to your organization's catalog and changes nothing that is running; installing a version into an environment is what moves an app. For an unattended pipeline, os cloud login --email … --password … skips the browser device flow — and note that under --json that command emits NDJSON: compact JSON documents, one per line. Parse its stdout line by line rather than with a single JSON.parse (see os cloud login).

The pages for shipping an app

PageWhat it answers
Publish, Versioning & PreviewCompile the artifact, publish a version, install it, and the preview patterns — including how to rehearse a pinned rollout locally
Validating MetadataThe mistakes a type-checker cannot see, and the one gate that rejects them before you ship

Upgrading the app

os migrate meta --from <major> replays every step between the major your metadata was authored against and this runtime's, in one pass; you then rebuild and ship as usual. See Upgrading → The metadata app.


Where the two meet

Three places, and each is where treating the two as one thing goes wrong:

  1. The engines.protocol handshake. The artifact declares which platform majors it can run on, and a runtime outside that range refuses the app rather than half-loading it. Everything else about the two version numbers is independent.

  2. The artifact source is an operator's input. Whoever runs the platform sets it, and it selects which version of the app boots. The sources have a fixed precedence, so a container that presets one variable cannot shadow a deliberate override:

    --artifact  >  OS_ARTIFACT_URL  >  OS_ARTIFACT_PATH  >  <cwd>/dist/objectstack.json
  3. The database. Moving either side can leave the physical schema shaped for the other. os migrate plan reports the drift, categorised safe / needs-confirm / destructive; os migrate apply reconciles it.

Every deployed app is AI-operable by default: an MCP server is served at /api/v1/mcp in every deployment, exposing your objects and actions to AI clients under the same permissions and RLS (set OS_MCP_SERVER_ENABLED=false to opt out). See MCP Server env vars and Your app as an MCP server.


Shared reference

Three pages belong to neither side and are read from both:

PageWhy both
CLI referenceOne command surface covers both jobs: os start and os migrate operate the runtime, while os validate, os compile, and os package publish ship the app
Environment VariablesThe canonical OS_* catalog. Configuration belongs to the host rather than to either shipped thing, which is exactly why it is neither side's page
Troubleshooting & FAQSymptom-first answers for validation, query, configuration, and performance problems on either side

On this page