# Apps

Deploy a project's websites to Vercel from the manifest, the CLI, or the SDK.

Canonical page: https://themachine.myapps.ai/docs/sdk/apps

An App is a website your project deploys to Vercel. Each App is an entry in the
`apps` list of the project manifest (`kortix.yaml`, or `kortix.toml` on older
projects), addressed by its slug. An App has a source, an optional build,
optional custom domains, and env vars. With no custom domain, the App uses the
`*.vercel.app` URL Vercel assigns.

Apps is an experimental feature and off by default. A project manager turns it
on under **Settings → Experimental → Apps**. Until then, every Apps route
answers `404` with a message that Apps are disabled for the project.

## Declare an App

```yaml
apps:
  - slug: marketing
    name: Marketing site
    source:
      type: git
      root_path: site
    build:
      command: npm run build
      out_dir: dist
    domains: [www.example.com]
    env:
      PUBLIC_API_URL: https://api.example.com
```

| Field | What it holds |
| --- | --- |
| `slug` | Required. Lowercase letters, digits, dashes, and underscores. Unique in the project. |
| `name` | Display name. Defaults to the slug. |
| `enabled` | Default `true`. Enabled Apps are redeployed automatically when their entry changes. |
| `source` | Required. `type: git` builds from a repo on every deploy: `repo` (default: this project's repo), `branch`, and `root_path`. `type: tar` deploys a tarball from `url`. |
| `build` | Optional `command` and `out_dir`. |
| `framework` | Optional build framework hint. Blank auto-detects. |
| `domains` | Optional custom domains. |
| `env` | Optional env vars for the deployed site, as string values. |

Machine sweeps Apps continuously: it starts a new pass as soon as the previous
one finishes, comparing each enabled App's deploy settings with its latest
deployment and redeploying the ones that changed or were never deployed. A
change usually starts deploying within seconds. Disabling an App does not take it down; stop it explicitly.

## Deploy from the CLI

`machine apps` manages Apps from your computer. Inside a session sandbox the
same commands run as `kortix apps`.

```sh
machine apps deploy ./site --app marketing
machine apps ls
machine apps logs marketing
```

| Command | Effect |
| --- | --- |
| `machine apps list` | List Apps and their latest deployment. Alias: `ls`. |
| `machine apps show <slug>` | Show one App. |
| `machine apps deploy [path]` | Publish a folder and deploy it. The folder is tarred locally, honoring `.gitignore`, `.dockerignore`, and `.kortixignore`. `--app <slug>` picks the App (default: the folder name). `--from-repo <folder>` archives a folder of the project repo instead. `--git` deploys from the repo on every deploy instead of a snapshot. |
| `machine apps create <slug>` | Create an App without deploying it. |
| `machine apps set <slug>` | Change an App. Only the flags you pass are sent. |
| `machine apps logs <slug>` | Read the latest deployment's logs. |
| `machine apps stop <slug>` | Take the current deployment out of service. |
| `machine apps delete <slug> [--yes]` | Remove the App from the manifest. |

`create`, `set`, and `deploy` accept `--name`, `--domain` (repeatable), `--env KEY=VALUE` (repeatable), `--framework`, `--build-command`, `--out-dir`, `--repo`, `--branch`, `--root`, `--tar-url`, and `--enabled` or `--disabled`. Every command accepts `--project`, `--host`, and `--json`.

## Deploy from the SDK

Import the App functions from the root `@kortix/sdk`. Each takes the project id
first and works on Apps by slug.

```ts
import { createProjectApp, deployProjectApp, listProjectApps } from '@kortix/sdk';

await createProjectApp(projectId, {
  slug: 'marketing',
  source: { type: 'git', repo: null, branch: null, root_path: 'site' },
  build: { command: 'npm run build', out_dir: 'dist' },
});

const result = await deployProjectApp(projectId, 'marketing');
console.log(result.status, result.deployment?.live_url);

const { apps, errors } = await listProjectApps(projectId);
```

| function | what |
| --- | --- |
| `listProjectApps(projectId)` | every App with its latest deployment, plus `errors` for manifest entries that do not parse |
| `createProjectApp(projectId, input)` · `updateProjectApp(projectId, slug, input)` | add · change an App's manifest entry |
| `deleteProjectApp(projectId, slug)` | remove an App from the manifest |
| `deployProjectApp(projectId, slug)` | deploy now; `status` is `active` or `failed` |
| `stopProjectApp(projectId, slug)` | take the current deployment out of service |
| `getProjectAppLogs(projectId, slug)` | the latest deployment's logs |
| `archiveProjectFolder(...)` | archive a folder of the project repo as a `tar` source |
| `listSessionAppFolders(...)` · `archiveSessionAppFolder(...)` | list · archive a folder from a running session's sandbox as a `tar` source |

A deployment's `status` is one of `pending`, `building`, `deploying`, `active`,
`failed`, or `stopped`. `live_url` holds the deployed URL.

> **Warn**
> The `kortix.project(id).apps` facade (`apps.create`, `apps.deployments.create`,
> `apps.access`, and the rest) targets an older sandbox-hosted Apps API that the
> server no longer serves. Its calls fail or return the wrong shape. Use the
> root functions above.

See [Deploying a website](/docs/guides/deploying-a-website) for a walkthrough.
