MachineMachine
MachineMachine
MachineGetting startedQuickstartAccounts & access
Your project
AgentsLegacy kortix.tomlManifest referenceModelsAgent permissionsSecrets
Running work
Change requestsRuntime & sandboxSessions
Connect & automate
ComputersConnectorsInkbox: iMessage, SMS, email & callsMCP serverPixio: images, video & audioRemindersSlack & channelsMicrosoft TeamsTriggers
Feature flags
Apps

Develop

CLI
TypeScript SDKFull exampleAuthenticationSign in with KortixSessionsAppsReact hooksSDK reference
Machine as a BackendAPI reference
GitHub
Feature flags

Apps

Deploy static sites, bundles, Dockerfiles, and OCI images to stable Kortix URLs.

A Kortix App is a provider-neutral serverless deployment owned by one project. An App owns one stable URL. Each deployment is immutable and numbered. A failed deployment never replaces live traffic.

Apps is a feature flag. Its stability is stable, and it is off by default. Turn it on per project before you deploy.

Building on Apps from TypeScript? See SDK → Apps for the client surface and the React hooks.

Turn Apps on

Open Settings → Experimental and switch Apps on for the project. You need project.settings.write.

While the flag is off:

  • Every Apps route answers 403 with { error, code: "feature_disabled", feature: "apps" }.
  • kortix apps <subcommand> prints the same sentence and exits 1.
  • The Apps entry does not appear in the project sidebar. Opening /projects/<id>/apps directly shows a gate screen that links to the flag. The page itself never enables the feature.

Source kinds

All four source kinds run on the same Kortix sandbox hosting backend. Kortix selects Daytona, Platinum, or E2B. They therefore share one deployment contract and one cold-wake contract.

KindDeploy thisKortix does
staticPlain HTML, CSS, JS, or a prebuilt SPA or dist/Serves the files
bundleA package sourceRuns the install and build commands, then serves the output directory
dockerfileA repository with a DockerfileBuilds the image, then runs your command on your port
oci_imageA public image referenceRuns your command on your port

Pick the fastest path for the result you want:

  • Build Vite locally and deploy dist/ as static for the lowest latency.
  • Deploy the package source as bundle when Kortix must run the install and build.
  • Export Next.js with output: 'export' and deploy out/ as static when the App needs no server runtime.
  • Deploy server-rendered Next.js and arbitrary services as dockerfile, with an explicit command and port.
  • Deploy an existing public image as oci_image, with an explicit command and port.

dockerfile and oci_image require --command and --port. static and bundle do not.

Deploy from the CLI

bash
kortix apps deploy .

deploy creates the App on first use, registers an immutable artifact — uploading a .tar.gz for a path, or recording the reference for --image — builds it, and blocks until the stable URL is ready. The wait budget is --wait-seconds, default 1200. Use --no-wait only when another process owns status tracking.

bash
kortix apps deploy dist --slug docs --access project
kortix apps deploy . --type dockerfile --command '["node","server.js"]' --port 3000
kortix apps deploy --image ghcr.io/acme/service:2026-08-07 --command '["node","server.js"]' --port 3000

The full subcommand list:

CommandWhat it does
kortix apps listList the project's Apps. --json.
kortix apps create <slug>Create an App without deploying it.
kortix apps deploy [path]Deploy a directory, a .tar.gz, or --image.
kortix apps set <id|slug>Change an existing App: --name, --cpu, --memory-gb, --disk-gb, --idle-timeout, --budget.
kortix apps show <id|slug>Show the App and its deployments; marks the live one. --json.
kortix apps logs <id|slug> [deployment]Read runtime logs. --after N --limit N.
kortix apps start <id|slug>Permit requests and start the App.
kortix apps stop <id|slug>Suspend compute now.
kortix apps rollback <id|slug> <deployment>Move traffic to a ready deployment.
kortix apps access <id|slug>Read or update the access policy.
kortix apps access-link <id|slug>Create a short-lived authenticated browser URL.
kortix apps delete <id|slug>Delete the App, its runtimes, and every deployment image. --yes.
kortix apps delete <id|slug> --deployment <id|vN>Delete one deployment and its image. Not the live one. --yes.

--project, --host, and --json work on every subcommand.

kortix apps set sends only the flags you pass, and needs project write access. --memory-gb accepts --memory and --disk-gb accepts --disk as aliases. --idle-timeout takes 120-86400 seconds. A machine or budget change applies to the next deployment, not to the running runtime.

Deployment defaults from kortix.yaml

An apps.<name> block holds local deploy defaults. The server stays the App control plane: the block never carries access, passwords, or member ids.

yaml
apps:
  docs:
    path: docs/dist
    type: static
    spa: true
    readiness_path: /
    idle_timeout_seconds: 300
    monthly_budget_usd: 5
    resources:
      cpu: 1
      memory_gb: 2
      disk_gb: 10
    env:
      PUBLIC_BASE: https://kortix.com
    secrets:
      API_TOKEN: docs_api_token

Select the block with kortix apps deploy --manifest-app docs. An explicit flag always wins over the block.

Machine, idle timeout, and budget

SettingDefaultBounds
cpu11 to 32 cores
memory_gb21 to 128 GiB
disk_gb101 to 500 GiB
idle_timeout_seconds300120 to 86400
monthly_budget_usd50 to 100000, or the operator's KORTIX_APPS_MAX_MONTHLY_BUDGET_USD

Apps reject a machine larger than the limits instead of clamping it. An App records its requested spec and bills off that record, so a silent downgrade would charge for compute the provider never gave. An out-of-range value answers 400 with code: "app_machine_out_of_range" or "app_budget_out_of_range".

Creating an App past the account's App quota answers 402 with code: "app_quota_exceeded". A duplicate slug in the same project answers 409.

The stable URL

Kortix assigns the hostname when the App is created and never changes it. On Kortix cloud it is <env>-<slug>-<route-key>.apps.kortix.com. Self-hosted deployments serve their own wildcard domain from KORTIX_APPS_BASE_DOMAIN.

An authorized request to a suspended App resumes its sandbox, waits for readiness, and proxies that same request. You do not have to wake it first.

While the App is waiting for its first deployment, queued, validating, building, provisioning, checking, activating, or starting:

  • A browser navigation gets a branded status page, HTTP 202, retry-after: 3, and a 3-second meta refresh.
  • A machine client gets 202 and JSON — for a cold start, { code: "app_starting" } with retry-after: 3.

Terminal and paused states answer differently:

StateHTTPcode
Deployment failed503app_deployment_failed
Deployment cancelled503app_deployment_cancelled
Monthly compute budget reached402app_budget_exceeded
Account cannot start compute402app_account_unfunded
Account at its concurrent-App limit429app_concurrency_limit

kortix apps stop suspends compute immediately; the next authorized request resumes the App. kortix apps start warms it before traffic arrives.

:::info[Cold starts stay invisible] The stable URL never exposes an app_stopped state. A provider edge that answers 502 during the first request after a resume is served as the ordinary cold-start page instead. A warm App owns its own HTTP status, including a deliberate application 502. :::

Access modes

An App's access mode is a per-resource visibility setting on top of the role model, not a role. It decides who can open this one App. It grants no permission the role verdict denies. See Accounts & access.

New Apps are private. Choose one mode:

ModeWho can open the App
privateThe creator only
projectEvery principal who can read the project
restrictedSelected users and groups
publicAnyone, with no authentication
passwordAnyone with the App password

Set it at deploy time or afterwards:

bash
kortix apps deploy . --access restricted --members m1,m2 --groups g1
kortix apps access docs --mode password --password 's3cret'
kortix apps access-link docs --json

Kortix access uses a five-minute exchange URL and an eight-hour, host-only, secure cookie. access-link mints that exchange URL without changing the policy — treat it as a secret.

Changing an access policy increments its revision, which revokes every existing App cookie. Passwords are Argon2id hashes; the API, the CLI, and the SDK never return a password or its hash.

:::warning[Never put an App password in your repo] kortix.yaml holds deployment defaults only. Pass a password with --password, or set it from the access modal. :::

Being able to see an App listed and being able to open it are different verdicts. A project manager sees every App in the project, so a private App stays manageable when its creator leaves. An account owner and an account admin hold manager-equivalent access on every project, so the same applies to them. The App record reports viewer_can_access for the second question.

Agents and Apps

An agent session can call an App with its session credential. The App gate checks that credential in Authorization: Bearer or in X-Kortix-App-Authorization: Bearer. Use X-Kortix-App-Authorization when the App reads Authorization for its own API key. The gate deletes X-Kortix-App-Authorization before it forwards the request, so the App never receives it. The gate also deletes an Authorization: Bearer header whose token is a Kortix credential (kortix_…), and it removes the Kortix App access and preview cookies from Cookie. Any other Authorization value and every other cookie reach the App unchanged. App code never receives a Kortix credential.

The gate judges a governed agent session as the agent, not as the person who started it. List the Apps an agent may open in kortix.yaml:

yaml
agents:
  report-writer:
    kortix_permissions: [project.app.read]
    apps: [reports-dashboard]   # App slugs, `all`, or `none` (the default)
App modeThe agent session is admitted when
publicAlways
projectproject.app.read is in the agent's effective permissions
restricted, privateThe App slug is in apps and project.app.read is effective
passwordNever

An agent session only opens Apps of its own project. A refused request answers 401 app_auth_required.

Three paths write the same apps list:

  • Dashboard — Customize → Agents → the agent → Apps. Pick App slugs, or choose All to cover Apps added later. The page appears only when this flag is on for the project.
  • CLI — kortix agents scope <agent> --apps reports-dashboard,example-org (also --apps all and --apps none). Needs a v2 kortix.yaml.
  • A change request that edits kortix.yaml directly.

The App's Access dialog reads the list back and shows every agent admitted to that App.

A connector whose base URL is an App of the same project (an openapi or http connector built from the App's OpenAPI document) needs no Kortix credential in its configuration. When an agent session calls it, the connector gateway adds a signed assertion for that session in X-Kortix-App-Authorization. The assertion names the calling session, binds to one App and one project, and expires after 60 seconds. The gateway never adds it for any other host.

Versions and rollback

Each deployment gets the next version number for its App and is immutable. The deployment record keeps its source kind, hosting provider, build and runtime spec, attempt count, and error code.

Every deployment also records who made it: created_by, actor_type (human, agent, service_account, or system), and the originating source_session_id when an agent deployed it.

Move traffic back to any ready deployment:

bash
kortix apps rollback docs <deployment-id>

Rollback starts the target deployment's runtime first, then stops the previous one. A target that fails to start leaves the current deployment serving.

Delete deployments and Apps

Each deployment builds one image on the hosting provider. Providers limit how many images an organization may hold, and an old deployment keeps its image so you can roll back to it. Delete what you no longer need:

bash
kortix apps show docs                               # v3 ready … live, v2 ready, v1 failed
kortix apps delete docs --deployment v1 --yes       # one deployment and its image
kortix apps delete docs --yes                       # the App and every image it built
  • The live deployment cannot be deleted (409 deployment_live). Roll back to another deployment first, or delete the App.
  • A deployment that is still building cannot be deleted (409 deployment_in_progress). Delete it after it finishes or fails.
  • A deleted deployment leaves show, the deployment list, and its logs, and can no longer receive rollback traffic.
  • The output reports how many images were freed. An image still held by a stopping runtime, or by a provider that did not answer, is reported as not released yet; Machine retries it automatically.

Failed deployments and deleted Apps also release their images without any action: project maintenance removes them every few minutes.

Each cold start compares the active deployment's runtime version against the current Kortix App runtime. The old deployment keeps serving while Kortix asynchronously builds one immutable replacement with the latest kortix-appd and Caddy binaries. A PostgreSQL advisory lock prevents duplicate refreshes.

The Apps page

Once the flag is on, an Apps row appears in the project sidebar, under Customize. The page is operational, not a creation surface: it lists the project's Apps with live state, a signed preview of each running App, and the access controls. Deploying is kortix apps deploy ..

An App with no active deployment reads Not deployed, never Running. A suspended App's preview issues the request that wakes it.

Kortix opens *.apps.kortix.com and *.apps.localhost on their direct origin rather than through a session's web forward proxy. That preserves the host-only access cookie and removes one network hop.

PreviousFeature flagsNextCLI

On this page

Turn Apps onSource kindsDeploy from the CLIDeployment defaults from kortix.yamlMachine, idle timeout, and budgetThe stable URLAccess modesAgents and AppsVersions and rollbackDelete deployments and AppsThe Apps page