# Deploy Coolify from a Quake.yaml manifest

Source: https://docs.quake.ai/resources/deployments/deploy-quake-yaml-to-coolify
Markdown: https://docs.quake.ai/resources/deployments/deploy-quake-yaml-to-coolify.md

---

# Deploy Coolify from a Quake.yaml manifest

Stand up a containerized app on a self-hosted [Coolify](https://coolify.io) instance from a single [`quake.yaml`](/resources/ai-assisted-development/quake-yaml) manifest using the [validated OpenTofu template](/docs/platform/validation#how-infrastructure-templates-are-checked) `coolify-host`. One manifest declares the app, its Postgres and Redis datastores, its secret names, and its domain. You validate the manifest, turn it into a [launch handoff packet](/resources/ai-assisted-development/launch), and run the Coolify consumer, which creates the application, provisions the managed datastores, injects the secrets by name, and triggers the deploy.

This is the automated counterpart to the click-through deploy in [Deploy Coolify with the coolify-host template](/resources/deployments/deploy-coolify-host-template), where you wire the app, database, and domain by hand in the dashboard. Here the manifest is the source of truth and the consumer does the wiring. You run Coolify yourself; this is not a managed service.

<Figure size="md" caption="What you'll build: a quake.yaml manifest, validated and prepared into a handoff packet, applied to a Coolify host by the consumer, which creates the app, provisions Postgres and Redis, and deploys">

```d2
direction: right

dev: You {shape: person}
manifest: quake.yaml
mcp: MCP server\n(validate + prepare)
packet: Handoff packet
consumer: Coolify consumer
coolify: Coolify host {
  app: App container
  pg: Postgres
  redis: Redis
  app -> pg
  app -> redis
}

dev -> manifest: author
manifest -> mcp
mcp -> packet
packet -> consumer
consumer -> coolify: create + deploy
```

</Figure>

<PricingCompanion
  components={[
    { kind: "template", slug: "coolify-host", required: true },
  ]}
/>

## Prerequisites

You need:

- A self-hosted Coolify instance you operate. Stand one up with [Deploy Coolify with the coolify-host template](/resources/deployments/deploy-coolify-host-template) if you do not have one.
- A Coolify API token (Coolify dashboard: **Keys & Tokens** > **API tokens**), and the project UUID and server UUID to create resources in.
- A git repository holding a containerized app with a `Dockerfile`. This walkthrough uses a Next.js app; any repo Coolify can build from a Dockerfile works.
- Python 3.9 or later to run the consumer (standard library only, no third-party packages).
- The reference Coolify consumer from `consumers/coolify/` in the platform repository.

## Step 1: Write the manifest

At the root of your app repository, create `quake.yaml`. It declares the runtime, the build source, a production and a preview environment, the two backing datastores, and the application secret names:

```yaml
version: 1
name: notes-app
runtime: container
source:
  build: dockerfile
  dockerfile: ./Dockerfile
environments:
  production:
    branch: main
    resources: cpu-standard
    domain: notes.example.com
  preview:
    branch: "*"
    resources: cpu-small
    ttl_hours: 72
services:
  - type: postgres
    name: db
  - type: redis
    name: cache
secrets:
  - NEXTAUTH_SECRET
evidence: true
```

The `services` entries name the datastores Coolify provisions: a Postgres named `db` and a Redis named `cache`. The `secrets` array lists names only; values stay out of the manifest and out of version control. For the full field set and validation rules, see the [`quake.yaml` reference](/resources/ai-assisted-development/quake-yaml).

## Step 2: Validate the manifest

Convert the manifest to JSON and validate it through the `validate_launch_manifest` MCP tool before you prepare a packet. The tool checks the schema and reports any resolution problems:

```bash
yq -o=json '.' quake.yaml > manifest.json

jq -n --slurpfile m manifest.json \
  '{jsonrpc:"2.0",id:1,method:"tools/call",
    params:{name:"validate_launch_manifest",arguments:{manifest:$m[0]}}}' \
  > validate.json

curl -sS https://docs.quake.ai/api/mcp \
  -H 'Content-Type: application/json' \
  -d @validate.json | jq '.result.structuredContent.content'
```

A valid manifest returns `"valid": true`. Fix any reported errors before continuing.

## Step 3: Prepare the handoff packet

Call `prepare_launch` with the manifest and a `deploy` action. The tool resolves the manifest into a handoff packet: the build plan, the resolved environment, the declared services, and the secret names the consumer reads from your environment:

```bash
jq -n --slurpfile m manifest.json \
  '{jsonrpc:"2.0",id:2,method:"tools/call",
    params:{name:"prepare_launch",
      arguments:{manifest:$m[0],action:"deploy"}}}' \
  > prepare.json

curl -sS https://docs.quake.ai/api/mcp \
  -H 'Content-Type: application/json' \
  -d @prepare.json | jq '.result.structuredContent.content' > handoff.json
```

`handoff.json` is the portable packet. The same packet runs against any consumer; Coolify is the one you use here. For the packet's structure, see [Launch handoff](/resources/ai-assisted-development/launch).

## Step 4: Export the credentials

The consumer reads secret values and the Coolify settings from the environment, not from the manifest, the packet, or any file under version control. Export the Coolify connection settings:

```bash
export COOLIFY_BASE_URL=https://coolify.example.com
export COOLIFY_API_TOKEN=...          # do not commit this
export COOLIFY_PROJECT_UUID=...
export COOLIFY_SERVER_UUID=...
```

Then export one value per application secret, plus a password for each managed datastore. The datastore passwords follow a per-service convention keyed by the service name in `UPPER_SNAKE` form:

```bash
export NEXTAUTH_SECRET=...             # the secrets[] entry
export DB_DB_PASSWORD=...              # postgres service "db"
export CACHE_REDIS_PASSWORD=...        # redis service "cache"
```

## Step 5: Run the consumer

Run the consumer against the packet. The manifest does not carry a git remote, so you pass the repository URL Coolify deploys from at invocation time:

```bash
python3 consumers/coolify/coolify_launch_consumer.py \
  --packet handoff.json \
  --git-repository https://github.com/me/notes-app \
  --out handoff.applied.json
```

The consumer maps the packet to Coolify's REST API: it creates the application from your git source with the Dockerfile build pack, provisions the Postgres and Redis as Coolify-managed databases, wires their connection strings into the app as `DB_DATABASE_URL` and `CACHE_REDIS_URL`, injects `NEXTAUTH_SECRET`, and triggers a deployment. It writes the updated packet to `handoff.applied.json` with the deploy id and preview URL it learned, and prints a summary.

Add `--no-deploy` to configure the application and datastores without triggering a deploy, which is useful for a dry run.

## Step 6: Verify the deploy

Open the Coolify dashboard and confirm the application shows as deploying, then running, with the Postgres and Redis resources alongside it. Watch the build and deploy logs stream in the dashboard.

Once the production deploy is healthy and the `notes.example.com` domain resolves to the host, Coolify's proxy serves the app over HTTPS. Confirm it responds:

```bash
curl -fsS https://notes.example.com/healthz
```

For domain and certificate setup, see step 6 of the [Coolify host walkthrough](/resources/deployments/deploy-coolify-host-template).

## Preview branches

The `preview` environment in the manifest sets `branch: "*"`, which the consumer maps to Coolify's per-pull-request preview deployments: open a pull request and Coolify builds and deploys a preview of that branch automatically. The manifest's `ttl_hours: 72` is advisory; Coolify has no API field for a preview lifetime, so prune stale previews in the dashboard or with your own cleanup job.

## What you built

- **Wrote one `quake.yaml`** declaring a containerized app, a Postgres and a Redis datastore, a secret, and a production domain
- **Validated the manifest** through the `validate_launch_manifest` MCP tool
- **Prepared a handoff packet** with `prepare_launch`
- **Ran the Coolify consumer**, which created the app, provisioned the datastores, injected the secret by name, and deployed
- **Confirmed the deploy** and saw how preview branches map to Coolify previews

## Scope of this deployment

This targets a self-hosted Coolify instance you operate, not a managed control plane. It is CPU-only and runs in one region, with no native CDN. The consumer triggers a deployment and reports the deploy id and preview URL; it does not wait for health checks or enforce the preview TTL. A service type Coolify has no managed equivalent for (for example `object-storage`) is reported and skipped rather than provisioned. You operate the Coolify host, the app, and the datastores: back them up, patch them, and watch resource use as you add apps.

## Next steps

- [Deploy Coolify with the coolify-host template](/resources/deployments/deploy-coolify-host-template): the click-through deploy this page automates, and the host you run the consumer against
- [How to execute a launch handoff packet from CI](/docs/automation/how-to/execute-launch-handoff-from-ci): run the same packet from GitHub Actions or GitLab CI instead of locally
- [`quake.yaml` reference](/resources/ai-assisted-development/quake-yaml): the full manifest field set and validation rules
- [Launch handoff](/resources/ai-assisted-development/launch): the packet structure and the validate-prepare-execute flow

## Clean up

Remove the application and its datastores from the Coolify dashboard (delete the app, the Postgres resource, and the Redis resource in your project). To tear down the Coolify host itself, run `tofu destroy` in the `coolify-host` template directory as shown in the [Coolify host walkthrough](/resources/deployments/deploy-coolify-host-template). Export anything you want to keep before you delete.
