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

> ## Agent Instructions
> These are the docs for Sevalla, a platform for deploying applications, databases, static sites, object storage and load balancers. The dashboard is at https://app.sevalla.com.
> Bold text in steps is an exact dashboard label.
> To act on a Sevalla account, prefer the Sevalla MCP server (https://mcp.sevalla.com/mcp, see https://docs.sevalla.com/ai-agents/overview.md), then the Sevalla CLI (https://docs.sevalla.com/developer-tools/cli.md), then the REST API (https://api-docs.sevalla.com, OpenAPI spec at https://api.sevalla.com/v3/openapi.json).
> Every page index is at https://docs.sevalla.com/llms.txt.

# Deploy a Quarkus application

> Deploy a Quarkus 3.40 application on Java 25 to Sevalla: create it on code.quarkus.io, listen on PORT, add SmallRye Health and graceful shutdown, and build with Ingot or a Dockerfile.

A Quarkus application runs on Sevalla on the JVM, as an application built from your Git repository: [Ingot](https://docs.sevalla.com/applications/builds/ingot.md), Sevalla's builder, recognizes the Quarkus Maven plugin in `pom.xml`, builds Quarkus's fast-jar with the project's Maven wrapper, and the web process starts it with `java -Dquarkus.http.port="$PORT" -jar /app/quarkus-run.jar`, so Quarkus listens on the port that Sevalla sets in the `PORT` environment variable.

## At a glance

| | |
| - | - |
| Source | A Git repository |
| Build | [Ingot](https://docs.sevalla.com/applications/builds/ingot.md) (Java 25, Maven), or the [Dockerfile](#deploy-with-a-dockerfile) |
| Start command | `java -Dquarkus.http.port="$PORT" -jar /app/quarkus-run.jar` |
| Port | The `PORT` environment variable, `8080` by default |
| Processes | Web process |
| Services | None |
| Disk | None |
| Health check | `GET /q/health/ready` returns `200` (readiness probe) |
| Size | **H1** for the web process |

### Environment variables

The application needs no environment variables of its own. It reads `PORT`, which Sevalla sets to the web process port.

## Before you begin

* A Sevalla company with a payment method, and a GitHub, GitLab or Bitbucket account for the repository. See [Git providers](https://docs.sevalla.com/git/overview.md).
* A Java 25 JDK on your computer. The project's Maven wrapper downloads Maven, so you don't install it.

## Create the project

Generate the project on [code.quarkus.io](https://code.quarkus.io): a Maven project for Java 25 with Quarkus REST and SmallRye Health.

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -o storefront.zip "https://code.quarkus.io/api/download?g=com.example&a=storefront&j=25&e=rest&e=smallrye-health&nc=true"
unzip storefront.zip && rm storefront.zip
cd storefront
```

| Parameter | What it does |
| - | - |
| `g=com.example`, `a=storefront` | The project's group and artifact ID, and its folder name |
| `j=25` | Compiles for Java 25 (`maven.compiler.release` in `pom.xml`) |
| `e=rest`, `e=smallrye-health` | Quarkus REST for the endpoints, and SmallRye Health for `/q/health/ready` and `/q/health/live` |
| `nc=true` | Leaves out the example code |

code.quarkus.io uses the recommended Quarkus platform release, 3.40.1.1 when this guide was written, and adds the Maven wrapper (`mvnw`), which runs Maven 3.9.16. It also adds Quarkus's Dockerfiles in `src/main/docker`, which package a build you've already run, and a `.dockerignore` for them that leaves out everything but `target/`. Ingot builds from source, so it doesn't apply that `.dockerignore`.

Add a resource for the home page:

```java src/main/java/com/example/storefront/HelloResource.java theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
package com.example.storefront;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/")
public class HelloResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello from Quarkus on Sevalla";
    }
}
```

The generated `.gitignore` already keeps the build output in `target/` and a local `.env` out of the repository.

## Prepare the project for Sevalla

Replace the empty `src/main/resources/application.properties` with:

```properties src/main/resources/application.properties theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
quarkus.http.port=${PORT:8080}
quarkus.shutdown.timeout=20s
```

| Setting | Why Sevalla needs it |
| - | - |
| `quarkus.http.port=${PORT:8080}` | Quarkus doesn't read `PORT`. This makes it listen on the port Sevalla sets, `8080` by default, and on port 8080 on your computer. Ingot also passes `-Dquarkus.http.port="$PORT"` on the command line; the setting gives a [Dockerfile](#deploy-with-a-dockerfile) build the same behavior. In production, Quarkus listens on all network interfaces. |
| `quarkus.shutdown.timeout=20s` | Turns on graceful shutdown. See [Shut down gracefully](#shut-down-gracefully). |

The rest of the project already has what Ingot needs:

| File | Why Sevalla needs it |
| - | - |
| `pom.xml` | Ingot recognizes a Maven project by it. It reads the Java version from `maven.compiler.release`, which is `25`, and recognizes Quarkus by `quarkus-maven-plugin`. See [Pin the Java version](https://docs.sevalla.com/guides/java/overview.md#pin-the-java-version). |
| `mvnw` and `.mvn/wrapper/maven-wrapper.properties` | Ingot builds with the wrapper, so the build runs the Maven version the project pins. The properties file also holds the checksum the wrapper verifies the Maven download with. Commit both. |

From these files, Ingot:

* Builds on the Java 25 JDK with `./mvnw --batch-mode --no-transfer-progress -DskipTests package`. Tests don't run in the image build; run them in CI.
* Copies Quarkus's fast-jar, the `target/quarkus-app` folder, into the image, dependencies first, so a code change leaves the dependency layer of the image as it is.
* Runs it on the Java 25 runtime (JRE) as user `1000:1000`, with `JAVA_TOOL_OPTIONS` set to `-XX:MaxRAMPercentage=75 -XX:+ExitOnOutOfMemoryError`. See [Size the JVM memory](https://docs.sevalla.com/guides/java/overview.md#size-the-jvm-memory).

Ingot runs Quarkus on the JVM only: it doesn't build a native executable, and stops the build when `quarkus.native.enabled` is `true`.

Run `./mvnw quarkus:dev` and open `http://localhost:8080` to check the application locally. Then commit everything and push it to your Git provider:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
git init
git add .
git commit -m "Prepare for Sevalla"
git branch -M main
git remote add origin https://github.com/acme/storefront.git
git push -u origin main
```

## Deploy to Sevalla

These steps build with [Ingot](https://docs.sevalla.com/applications/builds/ingot.md). To build from your own Dockerfile instead, see [Deploy with a Dockerfile](#deploy-with-a-dockerfile).

**1. Create the application**

In the sidebar, click **Applications**, then click **Create** > **Application**. Under **Source**, click **Private repository**, then choose the **Git provider**, the **Repository** and the **Branch**. Under **Location**, choose a **Data center**. Keep the **Size** at **H1** or choose a larger one, then click **Create application**. The application opens on its **Overview** tab with the status **Not deployed yet**: creating an application doesn't deploy it.

**2. Deploy**

Click the **Overview** tab, then click **Deploy now** under **Recent deployments**. Check the **Branch** and click **Deploy**.

**3. Turn on auto-deploy**

To deploy every push to the branch automatically, click the **Settings** tab, then click **Update auto-deploy** in the **Auto-deploy** section. Turn on **Auto-deploy** and click **Update auto-deploy**. See [Deployments](https://docs.sevalla.com/applications/deployments.md#deploy-automatically-on-push).

## Verify the deployment

1. On the **Deployments** tab, click the deployment. Its **Build log** shows Ingot's [build plan](https://docs.sevalla.com/applications/builds/ingot.md#read-the-build-plan): Java 25 from `maven.compiler.release` in `pom.xml`, Maven from the wrapper, and the start command for Quarkus.

   ```text Build log theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
   ╭─ ■ Quarkus · Java 25 ───────────────────────────────────────────────────────────────────────────────────────╮
   │ Java        25                                                          pom.xml maven.compiler.release "25" │
   │ Build tool  Maven                                                       mvnw                                │
   │ Framework   Quarkus                                                     pom.xml                             │
   │ Start       java -Dquarkus.http.port="$PORT" -jar /app/quarkus-run.jar  Quarkus                             │
   ├─ Image ─────────────────────────────────────────────────────────────────────────────────────────────────────┤
   │ Build       eclipse-temurin:25-jdk-resolute                                                                 │
   │ Runtime     eclipse-temurin:25-jre-resolute                                                                 │
   │ User        1000:1000                                                                                       │
   │ Init        tini                                                                                            │
   │ Port        $PORT, default 8080                                                                             │
   ╰────────────────────────────────────────────────────────────────────────────────────────────── Ingot v0.4.1 ─╯

   ! .dockerignore leaves out everything but build output, as for a Dockerfile that copies a finished build; Ingot builds from source, so it doesn't apply .dockerignore
   ```

   The warning is about the `.dockerignore` that code.quarkus.io generated: Ingot skips it and builds from the whole repository.
2. Wait for the deployment's status to change to **Deployed**. The application's status next to its name changes to **Running**.
3. Click the domain under the application's name, for example `storefront-x7k2m.sevalla.app`. The page shows `Hello from Quarkus on Sevalla`.

![The application header with its name, Running status, repository, branch and the domain that opens the application](https://assets.sevalla.com/screenshots/light/app-overview-address.png)

`/q/health/ready` returns a JSON document with `"status": "UP"`. The application's [runtime logs](https://docs.sevalla.com/applications/logs.md) show `Listening on: http://0.0.0.0:8080` and `Profile prod activated.` If the deployment fails, read its build log, then see [Troubleshoot](#troubleshoot).

To check the deployment from a terminal or an AI agent, read its `status` with [Get deployment](https://api-docs.sevalla.com/v3/applications/get-deployment) (`getDeploymentV3`) until it's `success`, and its build log with [Get application deployment logs](https://api-docs.sevalla.com/v3/applications/get-application-deployment-logs) (`getApplicationDeploymentLogsV3`), as in [Deploy with the API](#deploy-with-the-api). Then request the endpoints:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s https://storefront-x7k2m.sevalla.app/q/health/ready | jq -r .status
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
UP
```

[Get application runtime logs](https://api-docs.sevalla.com/v3/applications/get-application-runtime-logs) (`getApplicationRuntimeLogsV3`) with `search` finds the address Quarkus listens on:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s "https://api.sevalla.com/v3/applications/$APP_ID/runtime-logs?search=Listening%20on" \
  -H "Authorization: Bearer $SEVALLA_API_KEY" | jq -r '.[].message'
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
2026-10-30 05:32:37,648 INFO  [io.quarkus] (main) storefront 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.40.1.1) started in 3.785s. Listening on: http://0.0.0.0:8080
```

## Add a health check

SmallRye Health serves Quarkus's readiness check at `/q/health/ready`. A readiness probe on it makes each new instance wait until Quarkus has started before it gets traffic, so a deployment switches over only to instances that serve requests.

**1. Open the web process**

On the application's **Processes** tab, click **⋯** on the **Web** process, then click **Update process**.

**2. Turn on the readiness probe**

Under **Health checks**, turn on **Readiness probe** and set the **Path** to `/q/health/ready`. Keep the **Port** at the web process's port, `8080` unless you changed it.

**3. Save and deploy**

Click **Update process**, then click **Deploy** in the undeployed changes bar at the bottom of the page.

The deployment's status changes to **Deployed** once the new instance answers the probe. See [Health checks](https://docs.sevalla.com/applications/processes.md#health-checks) for every probe setting.

[Deploy with the API](#deploy-with-the-api) sets the same probe. [Get process](https://api-docs.sevalla.com/v3/applications/get-process) (`getProcessV3`) returns it in `readiness_probe`:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s https://api.sevalla.com/v3/applications/$APP_ID/processes/$WEB_ID \
  -H "Authorization: Bearer $SEVALLA_API_KEY" | jq -c .readiness_probe
```

```json theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
{"httpGet":{"path":"/q/health/ready","port":8080,"scheme":"HTTP"},"initialDelaySeconds":0,"periodSeconds":10,"timeoutSeconds":1,"successThreshold":1,"failureThreshold":3}
```

## Shut down gracefully

When Sevalla stops an instance, during a deployment, a restart or a scale-down, it waits 5 seconds, sends `SIGTERM`, and stops the instance if it's still running 30 seconds after the shutdown began. See [How processes run](https://docs.sevalla.com/applications/processes.md#how-processes-run).

Without `quarkus.shutdown.timeout`, Quarkus stops at once on `SIGTERM` and closes the connections of requests still in progress. With it, Quarkus waits for the requests in progress, up to 20 seconds, which ends within the 25 seconds between `SIGTERM` and the end of the shutdown. While it waits, the log shows `Waiting for HTTP requests to complete`, then `All HTTP requests complete`. The old instance's [runtime logs](https://docs.sevalla.com/applications/logs.md) end with `storefront stopped in`, followed by the time it took, on every deployment. Set the timeout in `application.properties`: set only as an environment variable, it doesn't turn graceful shutdown on.

## Deploy with a Dockerfile

Ingot needs no Dockerfile. Write your own when you want full control of the image: the base image, the system packages and every layer. Add a `Dockerfile` to the root of the repository, and replace the `.dockerignore` that code.quarkus.io generated:

```dockerfile Dockerfile theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
FROM maven:3.9-eclipse-temurin-25 AS build
WORKDIR /build
COPY pom.xml ./
RUN mvn --batch-mode --no-transfer-progress dependency:go-offline quarkus:go-offline
COPY src ./src
RUN mvn --batch-mode --no-transfer-progress -DskipTests package

FROM eclipse-temurin:25-jre-resolute
WORKDIR /app
COPY --from=build /build/target/quarkus-app/lib/ lib/
COPY --from=build /build/target/quarkus-app/*.jar ./
COPY --from=build /build/target/quarkus-app/app/ app/
COPY --from=build /build/target/quarkus-app/quarkus/ quarkus/
ENV JAVA_TOOL_OPTIONS="-XX:MaxRAMPercentage=75 -XX:+ExitOnOutOfMemoryError"
USER 1000:1000
EXPOSE 8080
CMD ["java", "-jar", "quarkus-run.jar"]
```

| Line or choice | Why |
| - | - |
| `maven:3.9-eclipse-temurin-25` | Maven 3.9, the line the wrapper pins, on the Java 25 JDK. The official image has Maven already, so the build doesn't download it. A line tag, not a digest, so each build gets Maven's, Java's and Ubuntu's security fixes. |
| `pom.xml` copied before the source | `dependency:go-offline` downloads the Maven plugins, and `quarkus:go-offline` the Quarkus artifacts the build resolves on its own, in a layer that Docker reuses until `pom.xml` changes. A code change downloads nothing again. |
| `-DskipTests` | Tests run in CI, not in the image build, as with Ingot. |
| Four `COPY` lines from `target/quarkus-app` | Quarkus's fast-jar layout, dependencies first, so a code change replaces only the small layers after `lib/`. `quarkus-run.jar` starts the application from these folders. |
| `eclipse-temurin:25-jre-resolute` | The Java 25 runtime without the compiler, on Ubuntu 26.04: the image Ingot runs Quarkus on. It has `/bin/sh` for the [web terminal](https://docs.sevalla.com/applications/web-terminal.md) and custom start commands. |
| `COPY` without `--chown`, then `USER 1000:1000` | The application runs as user `1000` (`ubuntu` in this image). Its files stay owned by root, so it can read them but not change them. |
| `JAVA_TOOL_OPTIONS` | Gives the heap 75% of the memory limit instead of 25%, and exits on `OutOfMemoryError` so Sevalla restarts the instance, as Ingot's image does. See [Size the JVM memory](https://docs.sevalla.com/guides/java/overview.md#size-the-jvm-memory). |
| `CMD ["java", "-jar", "quarkus-run.jar"]` | The exec form runs `java` as process 1, so it receives `SIGTERM` directly. The JVM handles `SIGTERM` itself and runs Quarkus's graceful shutdown, so the image needs no init process. |
| `EXPOSE 8080` | Documents Sevalla's default `PORT`. The application reads `PORT` through `quarkus.http.port`. |

```text .dockerignore theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
.git
target
.env*
*.log
```

The `.dockerignore` keeps the Git history, a local build in `target/`, local environment files and logs out of the build. The generated one leaves out everything but `target/`, for Quarkus's Dockerfiles in `src/main/docker`, so a Dockerfile that builds from source can't find `pom.xml` with it.

Commit and push both files. Ingot doesn't use the `Dockerfile`, so you can keep it in a repository that builds with Ingot. Ingot adds the `.dockerignore` patterns to its own, and its build plan shows `Ignored 4 patterns from .dockerignore`; none of them matches a file the Ingot build needs. Then switch the application to the Dockerfile build strategy:

**1. Choose the Dockerfile build strategy**

On the application's **Settings** tab, in the **Build strategy** section, click **Update build strategy**. Click **Dockerfile**, keep the **Dockerfile path** `Dockerfile` and the **Docker context** `.`, then click **Update build strategy**.

**2. Deploy**

Click the **Overview** tab, then click **Deploy now** under **Recent deployments**. Check the **Branch** and click **Deploy**.

The deployment's build log shows `📦 Building and pushing docker image using Dockerfile...` instead of Ingot's build plan, and its **Dockerfile** tab shows your file. When the deployment's status is **Deployed**, the domain shows `Hello from Quarkus on Sevalla` again. On the next deployment after a code change, the build log shows `CACHED` for the `go-offline` step. See [Dockerfile](https://docs.sevalla.com/applications/builds/dockerfile.md).

With the API, [Update application](https://api-docs.sevalla.com/v3/applications/update-application) (`updateApplicationV3`) switches the build strategy. Then deploy and wait as in [Deploy with the API](#deploy-with-the-api):

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -X PATCH https://api.sevalla.com/v3/applications/$APP_ID \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"build_type":"dockerfile","dockerfile_path":"Dockerfile","docker_context":"."}' \
  | jq -c '{build_type, dockerfile_path, docker_context}'
```

```json theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
{"build_type":"dockerfile","dockerfile_path":"Dockerfile","docker_context":"."}
```

The CLI does the same with `sevalla apps update $APP_ID --build-type dockerfile --dockerfile-path Dockerfile`. The new deployment's build log names the Dockerfile build:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s "https://api.sevalla.com/v3/applications/$APP_ID/deployments/$DEPLOYMENT_ID/logs?search=Building%20and%20pushing" \
  -H "Authorization: Bearer $SEVALLA_API_KEY" | jq -r '.[].message'
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
📦 Building and pushing docker image using Dockerfile...
```

## Deploy changes

With **Auto-deploy** on, every push to the branch starts a deployment; otherwise, click **Deploy now** for each change. Each deployment builds the image, then replaces the web process's instances. See [Deployments](https://docs.sevalla.com/applications/deployments.md).

## Use environment variables

Add configuration on the application's **Environment variables** tab, and read it in `application.properties` with a placeholder, as `quarkus.http.port=${PORT:8080}` reads `PORT`. Variables apply at the next deployment. With Ingot, variables marked **Available during buildtime** also reach the Maven build; with a Dockerfile, they arrive as build arguments, which a stage reads only after an `ARG` line for each one. Keep `quarkus.shutdown.timeout` in `application.properties`: as an environment variable alone, it doesn't turn graceful shutdown on. See [Environment variables](https://docs.sevalla.com/applications/environment-variables.md).

## Add a custom domain

To serve the application from your own domain, such as `shop.example.com`, add the domain on the application's **Domains** tab and create the DNS records that Sevalla shows. Custom domains need a web process larger than **H1**, so [scale](https://docs.sevalla.com/applications/scaling.md) the web process first. See [Custom domains](https://docs.sevalla.com/domains/overview.md).

## Troubleshoot

| Symptom | Cause | Fix |
| - | - | - |
| A Dockerfile build fails at `COPY pom.xml ./` with `"/pom.xml": not found` | The repository still has the `.dockerignore` that code.quarkus.io generates, which leaves out everything but `target/` | Replace it with the `.dockerignore` in [Deploy with a Dockerfile](#deploy-with-a-dockerfile) |
| The build log shows `✗ src/main/resources/application.properties quarkus.native.enabled builds a native executable, which Ingot doesn't build` | The project builds a native executable | Remove `quarkus.native.enabled`, or set it to `false`. To deploy a native executable, build it in your own Dockerfile. |
| Requests in progress fail during each deployment | `quarkus.shutdown.timeout` isn't set, or is set only as an environment variable | Set it in `application.properties`, see [Shut down gracefully](#shut-down-gracefully) |

For more causes, see [Troubleshoot Ingot builds](https://docs.sevalla.com/applications/builds/ingot.md#troubleshoot-ingot-builds) and [Troubleshoot builds and deployments](https://docs.sevalla.com/applications/troubleshooting/builds-and-deployments.md).

## Deploy with the API

These calls make the same deployment as [Deploy to Sevalla](#deploy-to-sevalla) and [Add a health check](#add-a-health-check), in an order that a script or an AI agent runs as it is. Each step names the [Sevalla API](https://docs.sevalla.com/developer-tools/api.md) operation, then the [CLI](https://docs.sevalla.com/developer-tools/cli.md) command and the [MCP server](https://docs.sevalla.com/ai-agents/overview.md) tool that do the same. You need:

* An [API key](https://docs.sevalla.com/developer-tools/api-keys.md) with the **Company developer** role, or the `APP:CREATE`, `APP:READ` and `APP:UPDATE` permissions, in the `SEVALLA_API_KEY` environment variable. The CLI reads the key from `SEVALLA_API_TOKEN`.
* The repository on a Git provider that's connected to your Sevalla account. See [Git providers](https://docs.sevalla.com/git/overview.md). Creating the application checks it: when Sevalla can't read the repository, the call returns `400` with `Cannot access repository https://github.com/acme/storefront: Repository not found or you don't have access.`, followed by where to grant access.
* `curl` and `jq`.

**1. Choose the location**

[List clusters](https://api-docs.sevalla.com/v3/resources/list-clusters) (`listClustersV3`) returns the locations your company can use, each with its `id`, the `display_name` that the dashboard shows and its region ID in `location`. Keep the ID of the one you want by its region ID, such as `eu-frankfurt-1` for Frankfurt, Germany. [Locations](https://docs.sevalla.com/platform/locations.md) lists them all:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
CLUSTER_ID=$(curl -s https://api.sevalla.com/v3/resources/clusters \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  | jq -r '.[] | select(.location == "eu-frankfurt-1") | .id')
```

CLI: `sevalla resources clusters`. MCP: `get_platform_options`.

**2. Create the application**

[Create application](https://api-docs.sevalla.com/v3/applications/create-application) (`createApplicationV3`) creates the application with a web process. It builds with Ingot (`build_type` is `ingot`) and isn't deployed yet:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
APP_ID=$(curl -s -X POST https://api.sevalla.com/v3/applications \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"display_name":"storefront","cluster_id":"'"$CLUSTER_ID"'","source":"privateGit","git_type":"github","repo_url":"https://github.com/acme/storefront","default_branch":"main"}' \
  | jq -r .id)
```

CLI: `sevalla apps create --name storefront --cluster $CLUSTER_ID --source privateGit --git-type github --repository https://github.com/acme/storefront --branch main`. MCP: `create_application` with `deploy` set to `false`.

**3. Find the domain**

[List application domains](https://api-docs.sevalla.com/v3/applications/list-application-domains) (`listApplicationDomainsV3`) returns the domain that Sevalla gives the application. It appears a few seconds after the application is created, so ask until it's there:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
for i in $(seq 1 24); do
  HOST=$(curl -s https://api.sevalla.com/v3/applications/$APP_ID/domains \
    -H "Authorization: Bearer $SEVALLA_API_KEY" | jq -r '.data[]? | select(.is_primary) | .name')
  [ -n "$HOST" ] && break
  sleep 5
done
echo "$HOST"
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
storefront-x7k2m.sevalla.app
```

CLI: `sevalla apps domains list --app-id $APP_ID`. MCP: `get_application`.

**4. Find the web process**

[List processes](https://api-docs.sevalla.com/v3/applications/list-processes) (`listProcessesV3`) returns the web process that the application was created with:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
WEB_ID=$(curl -s https://api.sevalla.com/v3/applications/$APP_ID/processes \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  | jq -r '.data[] | select(.type == "web") | .id')
```

CLI: `sevalla apps processes list --app-id $APP_ID`. MCP: `get_application`.

**5. Find the H1 size**

[List process resource types](https://api-docs.sevalla.com/v3/resources/list-process-resource-types) (`listProcessResourceTypesV3`) returns the sizes by `name`, in lowercase:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
H1_ID=$(curl -s https://api.sevalla.com/v3/resources/process-resource-types \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  | jq -r '.[] | select(.name == "h1") | .id')
```

CLI: `sevalla resources process-types`. MCP: `get_platform_options`.

**6. Set the size and the readiness probe**

The API creates the web process at **S1**, where the dashboard's default is **H1**. [Update process](https://api-docs.sevalla.com/v3/applications/update-process) (`updateProcessV3`) sets the size and adds the readiness probe from [Add a health check](#add-a-health-check), with the dashboard's default timings. Send `timeoutSeconds`: a probe without it gets 120 seconds, where the dashboard sets 1.

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -X PATCH https://api.sevalla.com/v3/applications/$APP_ID/processes/$WEB_ID \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"resource_type_id":"'"$H1_ID"'","readiness_probe":{"httpGet":{"path":"/q/health/ready","port":8080,"scheme":"HTTP"},"initialDelaySeconds":0,"periodSeconds":10,"timeoutSeconds":1,"successThreshold":1,"failureThreshold":3}}' \
  | jq -c '{resource_type_name, readiness_probe}'
```

CLI: `sevalla apps processes update $WEB_ID --app-id $APP_ID --resource-type $H1_ID` sets the size; the CLI can't set probes. MCP: `scale_process` with `size_id` for the size, and `sevalla_api_update` with `updateProcessV3` and the same body for the probe.

**7. Turn on auto-deploy**

[Update application](https://api-docs.sevalla.com/v3/applications/update-application) (`updateApplicationV3`) turns on automatic deployments for every push to the branch:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -X PATCH https://api.sevalla.com/v3/applications/$APP_ID \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"auto_deploy":true}' | jq .auto_deploy
```

CLI: `sevalla apps update $APP_ID --data '{"auto_deploy":true}'`. MCP: `sevalla_api_update` with `updateApplicationV3`.

**8. Deploy**

[Trigger deployment](https://api-docs.sevalla.com/v3/applications/trigger-deployment) (`triggerDeploymentV3`) deploys the latest commit on the branch:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
DEPLOYMENT_ID=$(curl -s -X POST https://api.sevalla.com/v3/applications/$APP_ID/deployments \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"branch":"main"}' | jq -r .id)
```

CLI: `sevalla apps deployments trigger $APP_ID --branch main`. MCP: `trigger_deployment`.

**9. Wait for the deployment**

[Get deployment](https://api-docs.sevalla.com/v3/applications/get-deployment) (`getDeploymentV3`) returns the deployment's `status`: `waiting` and `inProgress` while it runs, then `success`, `failed`, `cancelled` or `skipped`. Poll it until the status is final, for up to 30 minutes:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
for i in $(seq 1 120); do
  STATUS=$(curl -s "https://api.sevalla.com/v3/applications/$APP_ID/deployments/$DEPLOYMENT_ID" \
    -H "Authorization: Bearer $SEVALLA_API_KEY" | jq -r '.status // empty')
  case $STATUS in success|failed|cancelled|skipped) break ;; esac
  sleep 15
done
echo "$STATUS"
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
success
```

CLI: `sevalla apps deployments get $DEPLOYMENT_ID --app-id $APP_ID`. MCP: `get_deployment`.

**10. Read the build log**

[Get application deployment logs](https://api-docs.sevalla.com/v3/applications/get-application-deployment-logs) (`getApplicationDeploymentLogsV3`) returns the build log, oldest line first: the build plan from [Verify the deployment](#verify-the-deployment), the build and the rollout. When the status is `failed`, the last lines say why.

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s https://api.sevalla.com/v3/applications/$APP_ID/deployments/$DEPLOYMENT_ID/logs?limit=5000 \
  -H "Authorization: Bearer $SEVALLA_API_KEY" | jq -r '.[].message'
```

CLI: `sevalla apps deployments logs $DEPLOYMENT_ID --app-id $APP_ID`. MCP: `get_deployment_logs`.

**11. Check the application**

Request the home page from the application's domain:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -w '\n' https://$HOST/
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
Hello from Quarkus on Sevalla
```

Then run the other checks in [Verify the deployment](#verify-the-deployment).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.