Guides
Apps
Deploy from a source directory or a prebuilt image. Rolling deploys, secrets, logs, releases and rollbacks.
An app is a name with an address. It runs one or more machines from an image you deploy, or, for a static site, no machine at all. Machines, deploys, secrets, logs and releases all belong to an app.
Names and addresses
Section titled “Names and addresses”App names are unique across all of Rytiv: 2 to 63 characters, lowercase letters, digits and hyphens, starting with a letter. A few names are reserved for the platform (for example api, console, docs and www, and every name that is rytiv or starts with rytiv-).
An app answers on https://<app>.rytiv.app. Extra ports of a machine answer on https://<port>-<app>.rytiv.app.
Deploy from source
Section titled “Deploy from source”Point the CLI at a directory. Rytiv reads the project, builds it on its own machines and deploys the result:
ry deploy web --source .Or run ry alone in the directory: it signs you in if needed, shows what it detected, asks for an app name and deploys.
ryWhat is detected. Node.js projects with these frameworks: Next.js, SvelteKit, Nuxt, Remix, TanStack Start, SolidStart, Analog, Astro, Vite, Gatsby, Docusaurus, Create React App, VitePress, Eleventy and Angular, plus plain Node.js. A Dockerfile or Containerfile at the root of the directory wins over the detection; anything that is not Node.js needs one. ry detect shows the finding without changing anything.
Static sites (for example Astro without an adapter, Next.js with output: "export", Vite, or a folder with an index.html) need no machine: the built files are served directly.
rytiv.json
Section titled “rytiv.json”ry deploy reads a rytiv.json in the current directory or above it, so a deploy needs no flags. ry config init <app> writes one. A flag on the command line always wins over the file.
{ "app": "web", "source": ".", "port": 3000, "memoryMb": 512, "vcpus": 1}Other keys: image (instead of source), diskMb, buildMemoryMb, count, start, healthPath, healthTimeoutS, restart, killSignal, killTimeoutS, sleep and env. An unknown key is an error.
Deploy an image
Section titled “Deploy an image”ry deploy web --image nginx:alpine --port 80curl -X POST https://api.rytiv.app/v1/apps \ -H "Authorization: Bearer $RYTIV_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "web"}'
curl -X POST https://api.rytiv.app/v1/apps/web/deploy \ -H "Authorization: Bearer $RYTIV_TOKEN" \ -H "Content-Type: application/json" \ -d '{"image": "nginx:alpine", "internalPort": 80}'const api = "https://api.rytiv.app/v1";const headers = { Authorization: `Bearer ${process.env.RYTIV_TOKEN}`, "Content-Type": "application/json",};
await fetch(`${api}/apps`, { method: "POST", headers, body: JSON.stringify({ name: "web" }) });const res = await fetch(`${api}/apps/web/deploy`, { method: "POST", headers, body: JSON.stringify({ image: "nginx:alpine", internalPort: 80 }),});const deploy = await res.json(); // { id, status: "running", ... }POST /v1/apps answers 201, or 409 with name-taken if the name is used anywhere on Rytiv. POST /v1/apps/:name/deploy answers 202 with the deploy. Poll GET /v1/deploys/:id until status is done or error. On error, the answer names the reason in error and carries the last lines of the machine’s console in bootLog.
Deploy request
Section titled “Deploy request”| Field | Type | Default | Notes |
|---|---|---|---|
image |
string | required | An OCI reference such as nginx:alpine, or build:<id> for a build of yours |
internalPort |
integer | 3000 |
The port your app listens on |
memoryMb |
integer | kept, 512 for a new app |
128 to 16384 |
vcpus |
integer | kept, 1 for a new app |
1 to 16 |
diskMb |
integer | kept | 512 to 131072 |
count |
integer | kept, 1 for a new app |
Machines, 1 to 20 |
env |
object | {} |
Plain environment variables. Use secrets for credentials. |
start |
string | Start command, run through /bin/sh -c |
|
healthCheck |
object | path for an HTTP check (empty: the port only), timeoutMs, intervalMs, healthyThreshold, maxWaitMs |
|
restart |
object | policy: never or on-failure, with retries 1 to 10. Without it, a crashed machine is restarted. |
|
killSignal |
string | the image’s, else SIGTERM |
Sent before a machine is stopped or replaced |
killTimeoutS |
integer | 30 |
Seconds between that signal and SIGKILL, 1 to 300 |
“Kept” means: a deploy that does not name the field keeps what the app’s machines have. Every other field comes from the request or its default, so send internalPort, env and start with every deploy.
How a deploy rolls
Section titled “How a deploy rolls”A deploy starts a new machine, waits until it runs and answers on its port (and passes the health check, if you set one), then takes one old machine out of traffic and removes it, one at a time. If a new machine fails, the deploy stops, the new machine is discarded and the old version keeps serving.
An app with a volume works differently: its single machine stops before the new one starts, so there is a short gap.
Sleep when idle
Section titled “Sleep when idle”An app sleeps only if you give it a sleep rule. Without one, its machines run until you stop them. Name the idle time on a deploy:
ry deploy web --sleep 5mA machine that has had no requests and no CPU load for that long goes to sleep, and the next request wakes it. Up to 2 GB of memory it sleeps with its memory and resumes in about a quarter of a second; a larger machine stops instead and boots cold, and its files stay. --sleep off takes the rule away again, for a worker or a cron app that has to stay awake. In a deploy request the same rule is suspendPolicy, for example {"mode": "suspend", "idleSeconds": 300}.
Secrets
Section titled “Secrets”Secrets are environment variables stored encrypted. Nobody can read them back, not even you: the API lists names, never values.
ry secrets set web API_KEY=example-value OTHER_KEY=other-valuecurl -X PUT https://api.rytiv.app/v1/apps/web/secrets \ -H "Authorization: Bearer $RYTIV_TOKEN" \ -H "Content-Type: application/json" \ -d '{"secrets": {"API_KEY": "example-value"}, "staged": true}'| Method | Path | What it does |
|---|---|---|
PUT |
/v1/apps/:name/secrets |
{secrets, staged}. With staged: true (the default) the values apply at the next deploy. With staged: false Rytiv rolls the app now if a machine lacks the new value. |
GET |
/v1/apps/:name/secrets |
name, updatedAt and managed for every secret. Never a value. |
DELETE |
/v1/apps/:name/secrets/:key |
Removes one secret. 204. |
Secrets that Rytiv manages for you, such as the DATABASE_URL of an attached database, cannot be changed or removed this way. Each secret carries a build choice: whether the next source build sees it. A new secret is marked for the build only when its name starts with a public prefix such as NEXT_PUBLIC_ or VITE_; ry secrets set <app> KEY --build marks one, --no-build takes the mark away.
ry logs web -fGET /v1/apps/:name/logs answers {app, machines}, one entry per machine with the console output of that machine in text and a cursor. Pass cursor.<machineId>=<cursor> on the next call to get only what is new, and machine=<id> for one machine.
Logs are what your app’s machines write to their console.
Machines
Section titled “Machines”| Method | Path | What it does |
|---|---|---|
GET |
/v1/apps/:name/machines |
The app’s machines |
GET |
/v1/machines/:id |
One machine |
POST |
/v1/machines/:id/start |
Start a stopped or suspended machine |
POST |
/v1/machines/:id/stop |
Stop it |
POST |
/v1/machines/:id/suspend |
Suspend it |
POST |
/v1/machines/:id/destroy |
Remove it |
A machine is requested, scheduled, starting, running, suspending, suspended, stopping, stopped, deleted or failed.
ry machines webry exec web -- ls -la /appReleases and rollback
Section titled “Releases and rollback”Every deploy is a release. A rollback deploys an earlier release’s image again, without a rebuild, with the app’s current settings. Secrets, volumes and databases stay as they are.
ry releases webry rollback web| Method | Path | What it does |
|---|---|---|
GET |
/v1/apps/:name/releases |
The releases, which one runs, and which one a rollback would bring back |
POST |
/v1/apps/:name/rollback |
{} for the previous release that went live, or {version} or {releaseId}. Answers 202 with the deploy. |
Delete an app
Section titled “Delete an app”ry apps destroy webDELETE /v1/apps/:name removes the app and all its machines and answers 204. It cannot be undone. The CLI asks before it does this; pass --yes in scripts. An app that runs a database is removed with the database, not on its own.
Errors you will meet
Section titled “Errors you will meet”| Status | Code | When |
|---|---|---|
400 |
name-reserved |
The name is reserved for the platform |
409 |
name-taken |
The name is used somewhere on Rytiv |
403 |
org-limit-apps |
An account on the starting credit can have 10 apps, computers included. See Credit and pricing. |
402 |
credit-blocked |
The credit is used up: nothing new starts until a top-up. See Credit and pricing. |
404 |
build-not-found |
build:<id> is not a build of your organization |
409 |
deploy-in-flight |
Another deploy of this app is running |
409 |
volume-needs-single-machine |
An app with a volume runs exactly one machine |
See the CLI reference for every flag of ry deploy, and Apps and Deploys and releases in the API reference for every route with its fields. The guide Deploy a Next.js app walks the path from a directory to a URL.