> ## Documentation Index
> Fetch the complete documentation index at: https://www.towbar.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Apps

> Deploy source builds, static sites, OCI images, or multi-service Compose projects.

An app is a service declared in a GitHub or GitLab repository. Towbar can build a Dockerfile, static site, Railpack, Nixpacks, or Cloud Native Buildpacks project, or deploy a prebuilt OCI image. A Compose workload manages multiple services from repository-owned Compose files.

Towbar uses repository manifests for deployment configuration. The dashboard validates, previews, and operates the committed declaration without creating UI-only configuration. See [Deployment modes](/docs/platform-deployments) for mode, build-server, rollout, and Compose behavior.

<div className="towbar-doc-screenshot">
  <div className="towbar-product-light">
    <img src="https://mintcdn.com/avgeek/7IKQY5hBmeQaVMw0/assets/release-v2/app-overview-light.jpg?fit=max&auto=format&n=7IKQY5hBmeQaVMw0&q=85&s=daf8139c9ec81f603bf77ad80af2b8c9" alt="An app’s current state and latest deployment attempt appear in separate widgets." width="1280" height="720" loading="lazy" data-path="assets/release-v2/app-overview-light.jpg" />
  </div>

  <div className="towbar-product-dark">
    <img src="https://mintcdn.com/avgeek/7IKQY5hBmeQaVMw0/assets/release-v2/app-overview-dark.jpg?fit=max&auto=format&n=7IKQY5hBmeQaVMw0&q=85&s=1ac0203b23a8098abf4dfe7bbd52cd9e" alt="An app’s current state and latest deployment attempt appear in separate widgets." width="1280" height="720" loading="lazy" data-path="assets/release-v2/app-overview-dark.jpg" />
  </div>

  <p>
    An app’s current state and latest deployment attempt appear in separate
    widgets.
  </p>
</div>

## Define an app

These files define a service that listens on port 3000 and responds at `/health`:

```yaml title="towbar.yml" theme={"system"}
version: 2
environments:
  production:
    previews:
      enabled: true
```

```yaml title=".towbar/apps/web.app.yml" theme={"system"}
id: web
name: Web
server: 192.0.2.10
deployment:
  type: dockerfile
  dockerfile: Dockerfile
  context: .
container:
  port: 3000
  resources:
    cpus: 1
    memory: 1g
health:
  path: /health
  timeoutSeconds: 60
domains:
  primary: app.example.com
tls:
  mode: direct
environments:
  production: {}
```

Replace the server IP and domain, register the server, and point DNS at it before deploying. The Dockerfile must be inside the declared context. Configure the process to listen on the container's network interface, not only on its loopback address.

## Choose a health endpoint

Use an HTTP path that can respond without interactive authentication. The health timeout must allow the service to start. A passing build alone does not make the candidate ready for traffic.

Omit `domains` and `tls` for an app that does not need public routing. The dashboard describes it as **Not publicly exposed**. Private connectivity still needs the appropriate Docker network and host network rules.

## Supply configuration

Set build and runtime values in the app's [Secrets settings](/docs/secrets). Reference workspace or Repository values explicitly with `{{globals.KEY}}` or `{{source.KEY}}`; repository and workload values stay separate for production and previews. Global references intentionally reuse the workspace value. Use BuildKit secret mounts when a build needs credentials.

CPU and memory allocations are declared under `container.resources`. The inventory shows the configured capacity and observed usage relative to it; an unavailable measurement is not zero usage.

## Deploy and verify

Open the app and choose **Deploy**. Follow its stages until it reaches a terminal result, then verify the actual service response. Enable [automatic deployment](/docs/deployments#automatic-deployments) after the manual path works.

Use [deployment hooks](/docs/deployments#deployment-hooks) for required commands around promotion and [previews](/docs/previews) for pull request environments.

## Scheduled jobs

Declare recurring commands in the app manifest. Each run uses a short-lived
container from the deployed app image, with its runtime secrets, network,
resource limits and persistent volumes. It does not publish the app's ports or
claim its network alias.

```yaml theme={"system"}
jobs:
  - name: daily-report
    description: Generate the daily report
    command: ["node", "scripts/report.js"]
    schedule:
      cron: "0 2 * * *"
      timezone: UTC
    timeoutSeconds: 300
    enabled: true
```

Use a five-part cron expression; schedules have one-minute resolution and always
use UTC. Commands are argument arrays and retain the image's entrypoint and
user. To use shell operators, explicitly run a shell such as
`["sh", "-c", "node report.js && node notify.js"]`.

The **Scheduled jobs** page shows configured jobs and the latest 100 runs.
Members with workload-operation access can use **Run now**; viewers can read
status and output. Output is bounded to 256 KiB and known runtime secret values
are redacted. Keep credentials out of command arguments and output.

Deploy after changing the app manifest. Jobs wait until that configuration is
deployed. A queued run is rejected if its release or declaration changes before
execution. Jobs share the app's work queue with deployments and do not overlap
with another run of the same job. Commands that exceed their time limit are
stopped; failed or interrupted commands are not retried automatically. Make
commands idempotent if you intend to rerun them manually.

Repository and environment automation pauses also pause scheduled jobs. Preview
environments never schedule jobs. Missed schedules during pauses, outages or
longer runs are skipped; Towbar does not replay a backlog. Set `enabled: false`
or override `jobs: []` in an environment to disable its scheduled work.
