> ## 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 Hugo site

> Deploy a Hugo site to Sevalla as a free static site that installs Hugo with hugo-bin, or as an application built from a Dockerfile that serves the site with Caddy.

A Hugo site builds to static files: `hugo build` writes every page as HTML to the `public` folder. Sevalla publishes that folder as a static site, served from Cloudflare's edge and free up to 100 GB of bandwidth a month. The static site build runs on Node.js and has no Hugo, so the project installs Hugo as an npm package, `hugo-bin`. To run the site as an [application](#deploy-with-a-dockerfile) instead, build it from a Dockerfile.

## At a glance

| | |
| - | - |
| Source | A Git repository, with the Ananke theme as a Git submodule |
| Build | Static site: `npm run build`, which runs `hugo build --minify` with the Hugo release `hugo-bin` installs, on Node.js **Latest LTS**, publishing `public`. Application: the [Dockerfile](#deploy-with-a-dockerfile) only; Ingot has no Hugo builder |
| Start command | Application: `caddy run --config /etc/caddy/Caddyfile --adapter caddyfile`, the `Dockerfile`'s `CMD` |
| Port | Application: the `PORT` environment variable, `8080` by default |
| Processes | Application: web process |
| Disk | None |
| Size | Static site: none to choose. Application: **H1** for the web process |

### Environment variables

| Variable | Required | Available during | Secret | Value |
| - | - | - | - | - |
| `HUGO_BASEURL` | Yes | Build | No | The site's address with `https://` and a trailing slash, such as `https://storefront-blog-x7k2m.sevalla.page/` or `https://storefront-x7k2m.sevalla.app/`. Without it, links use `https://example.org/` from `hugo.toml` |

## 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).
* Hugo 0.160 or later and Git on your computer. See [Install Hugo](https://gohugo.io/installation/).
* Node.js 24 or later on your computer, for `hugo-bin`.

## Create the project

Create a site and add the Ananke theme as a Git submodule, as in Hugo's quick start:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
hugo new site storefront
cd storefront
git init
git submodule add https://github.com/gohugo-ananke/ananke themes/ananke
```

Turn on the theme and name the site in `hugo.toml`:

```toml hugo.toml theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
baseURL = 'https://example.org/'
locale = 'en-us'
title = 'Storefront'
theme = 'ananke'
```

Add a first post:

```markdown content/posts/welcome.md theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
+++
title = 'Welcome to Storefront'
date = 2026-10-29T09:00:00Z
+++

Storefront's blog runs on Sevalla.
```

Keep Hugo's output and local files out of the repository:

```text .gitignore theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
public/
resources/
node_modules/
.hugo_build.lock
```

## Prepare the project for Sevalla

Install Hugo as a development dependency, and add a `build` script that runs it:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
npm init -y
npm install hugo-bin --save-dev
npm pkg set scripts.build="hugo build --minify"
```

| File | Why Sevalla needs it |
| - | - |
| `package.json` `devDependencies` | `hugo-bin` downloads the Hugo release it's pinned to from Hugo's GitHub releases when npm installs it (Hugo 0.169.0 for `hugo-bin` 0.167.0), and puts `hugo` in `node_modules/.bin`, where the build command finds it. |
| `package.json` `scripts.build` | The static site's **Build command** runs it. `--minify` makes the HTML, CSS and JavaScript smaller. |
| `package-lock.json` | The build installs the same `hugo-bin` version, and so the same Hugo release, every time. |
| `.gitmodules` | Sevalla clones submodules with the repository, so the theme is there when the site builds. |

Hugo writes absolute links with `baseURL` from `hugo.toml`, which `hugo new site` sets to `https://example.org/`. On Sevalla, you set the real address in the `HUGO_BASEURL` environment variable, which Hugo reads instead, so the same repository builds for every domain.

Run `npx hugo server` and open `http://localhost:1313` to check the site locally. Then commit everything and push it to your Git provider:

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

## Deploy as a static site

**1. Choose the repository**

In the sidebar, click **Static sites**, then click **Create static site**. Under **Source**, click **Private repository**, then choose the **Git provider**, the **Repository** and the **Branch**.

**2. Set the build settings**

Under **Build settings**, Sevalla fills in `npm run build` and `dist` from `package.json`. Hugo builds to `public`, so change the **Publish directory**:

| Field | Value |
| - | - |
| **Build site before publishing** | On |
| **Node version** | **Latest LTS** |
| **Build command** | `npm run build` |
| **Root directory** | Empty, for the repository root |
| **Publish directory** | `public` |

**3. Create the static site**

Enter a **Name** under **Details**, then click **Create static site**. Sevalla starts the first deployment right away, and deploys every push to the branch while **Auto-deploy** is on.

**4. Set the site's address**

Click the **Environment variables** tab, then click **Add environment variables**. Enter `HUGO_BASEURL` as the **Key** and the site's address as the **Value**, with `https://` and a trailing slash, for example `https://storefront-x7k2m.sevalla.page/`. The domain is in the **Details** card on the **Overview** tab. Click **Add environment variables**.

**5. Deploy again**

Click the **Deployments** tab, click **Deploy now**, then click **Deploy**. The variable applies from this deployment on.

The build log shows the Hugo release that `hugo-bin` installed, such as `hugo v0.169.0`, then Hugo's summary of the pages it built. npm 11 warns there that `hugo-bin` has an install script not yet covered by `allowScripts`; it runs the script anyway. See [Build settings](https://docs.sevalla.com/static-sites/build-settings.md) for every field.

### Verify the static site

1. On the **Deployments** tab, wait for the deployment's status to change to **Deployed**. The site's **Status** on the **Overview** tab changes to **Live**.
2. On the **Overview** tab, click **Visit site**. The Ananke home page opens with the title **Storefront** and the post **Welcome to Storefront**, and the site title's link points to the site's own domain.
3. From a terminal, with your site's domain:

   ```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
   curl -s https://storefront-blog-x7k2m.sevalla.page/ | grep -o '<link rel=canonical[^>]*>'
   ```

   The output is `<link rel=canonical href=https://storefront-blog-x7k2m.sevalla.page/>`: Hugo built the site with `HUGO_BASEURL`. With the API, [Get static site deployment](https://api-docs.sevalla.com/v3/static-sites/get-static-site-deployment) returns the deployment's status; see [Deploy with the API](#deploy-with-the-api).

![The static site's Details card with its domain, Live status, source repository and the Visit site button](https://assets.sevalla.com/screenshots/light/static-site-overview-visit.png)

If the canonical link points to `example.org`, `HUGO_BASEURL` isn't set for the deployment: add it and deploy again. If the deployment fails, see [Troubleshoot static sites](https://docs.sevalla.com/static-sites/troubleshooting.md).

## Deploy with a Dockerfile

Ingot, the default build strategy for applications, has no Hugo builder, so a Hugo site runs as an application only from a Dockerfile. Use one when the site needs something only applications have, such as promoting one build through the stages of a [pipeline](https://docs.sevalla.com/pipelines/overview.md). Add a `Dockerfile`, a `Caddyfile` and a `.dockerignore` to the root of the repository:

```dockerfile Dockerfile theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
FROM ghcr.io/gohugoio/hugo:v0.169.0 AS build
WORKDIR /project
COPY . .
ARG HUGO_BASEURL
RUN hugo build --minify

FROM caddy:2-alpine AS caddy
RUN setcap -r /usr/bin/caddy

FROM alpine:3
COPY --from=caddy /usr/bin/caddy /usr/bin/caddy
COPY --from=caddy /etc/mime.types /etc/mime.types
COPY Caddyfile /etc/caddy/Caddyfile
COPY --from=build --chown=root:root /project/public /srv
ENV XDG_CONFIG_HOME=/tmp XDG_DATA_HOME=/tmp
USER 1000:1000
EXPOSE 8080
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]
```

```text Caddyfile theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
{
	admin off
	auto_https off
	persist_config off
}

:{$PORT:8080} {
	root * /srv
	encode zstd gzip
	file_server

	handle_errors 404 {
		rewrite * /404.html
		file_server
	}
}
```

| Line or choice | Why |
| - | - |
| `ghcr.io/gohugoio/hugo:v0.169.0` | Hugo's official image, for the build only. Hugo publishes it for each release, with no tag that follows a line, so the tag names the release your site is built and tested with. Update it when you update Hugo. The image builds as its own `hugo` user, which owns `/project`. |
| `ARG HUGO_BASEURL` | Sevalla passes every variable marked **Available during buildtime** as a build argument, and Hugo reads `HUGO_BASEURL` from the environment. It's declared in the build stage only, so it doesn't show in the final image's history. |
| Three stages | The `build` stage runs Hugo. The `caddy` stage takes Caddy from its official image and removes the file capability that lets it bind ports below 1024, which a server running as a regular user on port 8080 doesn't need. The final image is Alpine Linux with Caddy and `public`: no Hugo and no source. |
| `--chown=root:root` | The build stage's files belong to its `hugo` user. In the final image they belong to root, so the server can read them but not change them. |
| `USER 1000:1000` | Caddy runs as a regular user, not root. Caddy keeps its state in `/tmp`, which `XDG_CONFIG_HOME` and `XDG_DATA_HOME` point to. |
| `handle_errors 404` | Answers missing pages with the theme's `404.html` and status `404`. Folder URLs such as `/posts/welcome` redirect to `/posts/welcome/`, which serves `index.html`. |
| `:{$PORT:8080}` | Caddy listens on `PORT`, which Sevalla sets to the web process's port, or `8080` when it isn't set. Caddy stops gracefully on `SIGTERM` by itself, so the image needs no init process. |

```text .dockerignore theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
.git
node_modules
public
resources
.hugo_build.lock
.env*
Dockerfile
.dockerignore
```

The build stage doesn't install `hugo-bin`, so the site builds the same way with or without the static site setup. Sevalla clones the theme's submodule for applications too. Commit and push the three files, then create the application:

**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. Choose the Dockerfile build strategy**

On the **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**.

**3. Set the site's address**

Click the **Environment variables** tab, then click **Add environment variables**. Enter `HUGO_BASEURL` as the key and the application's address as the value, with `https://` and a trailing slash, for example `https://storefront-x7k2m.sevalla.app/`. The domain is under the application's name in the page header. Keep **Available during buildtime** selected and click **Add environment variables**.

**4. 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...`, then Hugo's summary of the pages it built, and its **Dockerfile** tab shows your file. When the status changes to **Deployed**, click the domain under the application's name: the Ananke home page opens with the post **Welcome to Storefront**. From a terminal, `curl -s https://storefront-x7k2m.sevalla.app/ | grep -o '<link rel=canonical[^>]*>'` prints `<link rel=canonical href=https://storefront-x7k2m.sevalla.app/>`. If you deploy before you switch the build strategy, Ingot fails or starts a server that doesn't exist: switch to **Dockerfile** and deploy again. See [Dockerfile](https://docs.sevalla.com/applications/builds/dockerfile.md).

![The Update build strategy sheet with Dockerfile selected, the Dockerfile path, the Docker context and the Docker registry credential](https://assets.sevalla.com/screenshots/light/app-settings-build-strategy-dockerfile.png)

## Deploy changes

With **Auto-deploy** on, every push to the branch starts a deployment of the static site or the application; otherwise, deploy each change from the **Deployments** tab. To move to a newer Hugo release, update `hugo-bin` with `npm install hugo-bin@latest --save-dev` for the static site, and the image tag in the `Dockerfile` for the application. See [Static site deployments](https://docs.sevalla.com/static-sites/deployments.md) and [Deployments](https://docs.sevalla.com/applications/deployments.md).

## Add a custom domain

To serve the site from your own domain, such as `blog.example.com`, add the domain on the static site's **Domains** tab and create the DNS records that Sevalla shows, then set `HUGO_BASEURL` to `https://blog.example.com/` and deploy again. Applications have a **Domains** tab too, but custom domains need a web process larger than **H1**. See [Custom domains](https://docs.sevalla.com/domains/overview.md).

## Deploy with the API

This sequence creates the static site from [Deploy as a static site](#deploy-as-a-static-site) and the application from [Deploy with a Dockerfile](#deploy-with-a-dockerfile) through the [Sevalla API](https://docs.sevalla.com/developer-tools/api.md), so an agent or a script can run it as is. Run the first five steps for the static site, the rest for the application. Each step names the operation, shows the `curl` command, and gives the matching [CLI](https://docs.sevalla.com/developer-tools/cli.md) command and [MCP server](https://docs.sevalla.com/ai-agents/overview.md) tool.

You need:

* An [API key](https://docs.sevalla.com/developer-tools/api-keys.md) with the **Company developer** role, in the `SEVALLA_API_KEY` environment variable. The CLI reads the same key from `SEVALLA_API_TOKEN`.
* `curl` and `jq`, and the project pushed to GitHub as in [Prepare the project for Sevalla](#prepare-the-project-for-sevalla).
* A GitHub account that can read the repository, connected to Sevalla. See [Git providers](https://docs.sevalla.com/git/overview.md). The API can't list connected accounts: when none can read the repository, [Create static site](https://api-docs.sevalla.com/v3/static-sites/create-static-site) and [Create application](https://api-docs.sevalla.com/v3/applications/create-application) fail with `400` and `Cannot access repository https://github.com/acme/storefront: Repository not found or you don't have access.`

A call that fails returns `status` and `message` instead of the resource, and `jq -r .id` prints `null`: stop and read the message.

**1. Create the static site**

[Create static site](https://api-docs.sevalla.com/v3/static-sites/create-static-site) (`createStaticSiteV3`) takes the build settings: `node_version` `lts` is the dashboard's **Latest LTS**, and `published_directory` is the **Publish directory**.

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
SITE_ID=$(curl -s https://api.sevalla.com/v3/static-sites \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<JSON | jq -r .id
{
  "display_name": "storefront-blog",
  "source": "privateGit",
  "git_type": "github",
  "repo_url": "https://github.com/acme/storefront",
  "default_branch": "main",
  "build_command": "npm run build",
  "published_directory": "public",
  "node_version": "lts",
  "auto_deploy": true
}
JSON
)
```

CLI: `sevalla static-sites create --name storefront-blog --repository https://github.com/acme/storefront --branch main --source privateGit --git-type github --build-command "npm run build" --publish-directory public --node-version lts`. MCP: `create_static_site` with the same fields.

**2. Set the site's address**

[Get static site](https://api-docs.sevalla.com/v3/static-sites/get-static-site) (`getStaticSiteV3`) returns the site's domain in `hostname`, a few seconds after the site is created; until then it's `null`. [Create static site environment variable](https://api-docs.sevalla.com/v3/static-sites/create-static-site-environment-variable) (`createStaticSiteEnvVarV3`) adds `HUGO_BASEURL`, with a trailing slash.

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
for i in $(seq 1 30); do
  SITE_HOST=$(curl -s https://api.sevalla.com/v3/static-sites/$SITE_ID \
    -H "Authorization: Bearer $SEVALLA_API_KEY" | jq -r '.hostname // empty')
  [ -n "$SITE_HOST" ] && break
  sleep 5
done
SITE_URL=https://$SITE_HOST
curl -s https://api.sevalla.com/v3/static-sites/$SITE_ID/env-vars \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"key\": \"HUGO_BASEURL\", \"value\": \"$SITE_URL/\"}" | jq -r .key
```

CLI: `sevalla static-sites get "$SITE_ID"` and `sevalla static-sites env-vars create "$SITE_ID" --key HUGO_BASEURL --value "$SITE_URL/"`. MCP: `get_static_site`, then `set_environment_variables` with `scope` `static_site`.

**3. Deploy the static site**

[Deploy static site](https://api-docs.sevalla.com/v3/static-sites/deploy-static-site) (`deployStaticSiteV3`) starts the first deployment. Unlike the dashboard, creating a static site through the API doesn't start one.

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
SITE_DEPLOYMENT_ID=$(curl -s https://api.sevalla.com/v3/static-sites/$SITE_ID/deployments \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}' | jq -r .id)
```

CLI: `sevalla static-sites deployments trigger "$SITE_ID"`. MCP: `trigger_deployment` with `service_type` `static_site`.

**4. Wait for the static site deployment**

[Get static site deployment](https://api-docs.sevalla.com/v3/static-sites/get-static-site-deployment) (`getStaticSiteDeploymentV3`) returns the deployment's `status`: `waiting`, then `inProgress`, then `success` or `failed`. The loop polls every 15 seconds for up to 30 minutes and keeps polling through a failed request.

```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/static-sites/$SITE_ID/deployments/$SITE_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"
```

If it's `failed`, [Get static site deployment logs](https://api-docs.sevalla.com/v3/static-sites/get-static-site-deployment-logs) (`getStaticSiteDeploymentLogsV3`) returns the build log. CLI: `sevalla static-sites deployments get "$SITE_DEPLOYMENT_ID" --site-id "$SITE_ID"` and `sevalla static-sites deployments logs "$SITE_DEPLOYMENT_ID" --site-id "$SITE_ID"`. MCP: `get_deployment` and `get_deployment_logs` with `service_type` `static_site`.

**5. Check the static site**

The home page has the site's title, and its canonical link uses `HUGO_BASEURL`. These commands print `<title>Storefront</title>`, then `<link rel=canonical href=https://storefront-blog-x7k2m.sevalla.page/>` with your site's domain:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s $SITE_URL/ | grep -o '<title>[^<]*</title>'
curl -s $SITE_URL/ | grep -o '<link rel=canonical[^>]*>'
```

**6. Look up the location and the size**

[List clusters](https://api-docs.sevalla.com/v3/resources/list-clusters) (`listClustersV3`) returns every location your company can use, with its region ID. This guide uses Frankfurt, Germany, `eu-frankfurt-1`. [List process resource types](https://api-docs.sevalla.com/v3/resources/list-process-resource-types) (`listProcessResourceTypesV3`) returns the process sizes.

```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')
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 clusters` and `sevalla resources process-types`. MCP: `get_platform_options`.

**7. Create the application**

[Create application](https://api-docs.sevalla.com/v3/applications/create-application) (`createApplicationV3`) creates the application with a web process and doesn't deploy it.

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

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`.

**8. Size the web process**

The API creates the web process at **S1**, while the dashboard creates it at **H1**, which is enough for Caddy. [List processes](https://api-docs.sevalla.com/v3/applications/list-processes) (`listProcessesV3`) returns the web process, and [Update process](https://api-docs.sevalla.com/v3/applications/update-process) (`updateProcessV3`) sets its size. Keep **S1**, and skip this step, to add a custom domain later.

```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')
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\"}" | jq -r .resource_type_name
```

CLI: `sevalla apps processes update "$WEB_ID" --app-id "$APP_ID" --resource-type "$H1_ID"`. MCP: `scale_process` with `size_id` and `apply_now` set to `false`.

**9. Choose the Dockerfile build strategy**

[Update application](https://api-docs.sevalla.com/v3/applications/update-application) (`updateApplicationV3`) sets the build strategy. Ingot has no Hugo builder, so deploy only after this step.

```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": ".", "auto_deploy": true}' | jq -c '{build_type, auto_deploy}'
```

The same call turns on auto-deploy. CLI: `sevalla apps update "$APP_ID" --data` with the same body. MCP: `sevalla_api_update` with `updateApplicationV3` and the same body.

**10. Set the site's address**

[List application domains](https://api-docs.sevalla.com/v3/applications/list-application-domains) (`listApplicationDomainsV3`) returns the application's domain, and [Create environment variable](https://api-docs.sevalla.com/v3/applications/create-environment-variable) (`createEnvironmentVariableV3`) adds `HUGO_BASEURL`, available during the build only: the `Dockerfile` reads it as a build argument.

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
APP_URL=https://$(curl -s https://api.sevalla.com/v3/applications/$APP_ID/domains \
  -H "Authorization: Bearer $SEVALLA_API_KEY" | jq -r '.data[] | select(.is_primary) | .name')
curl -s https://api.sevalla.com/v3/applications/$APP_ID/env-vars \
  -H "Authorization: Bearer $SEVALLA_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"key\": \"HUGO_BASEURL\", \"value\": \"$APP_URL/\", \"is_runtime\": false, \"is_buildtime\": true}" | jq -r .key
```

CLI: `sevalla apps domains list --app-id "$APP_ID"` and `sevalla apps env-vars create "$APP_ID" --key HUGO_BASEURL --value "$APP_URL/"`, which makes it available during runtime too. MCP: `get_application`, then `set_environment_variables` with `runtime` `false` and `buildtime` `true`.

**11. Deploy**

[Trigger deployment](https://api-docs.sevalla.com/v3/applications/trigger-deployment) (`triggerDeploymentV3`) builds the latest commit of the branch and rolls it out.

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

CLI: `sevalla apps deployments trigger "$APP_ID"`. MCP: `trigger_deployment`.

**12. Wait for the deployment**

[Get deployment](https://api-docs.sevalla.com/v3/applications/get-deployment) (`getDeploymentV3`) returns the deployment's `status`: `waiting`, then `inProgress`, then `success` or `failed`. The loop polls every 15 seconds for up to 30 minutes and keeps polling through a failed request.

```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"
```

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

**13. Check the application**

[Get application deployment logs](https://api-docs.sevalla.com/v3/applications/get-application-deployment-logs) (`getApplicationDeploymentLogsV3`) returns the build log, which shows Hugo's summary and, on a failed deployment, ends with the error:

```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'
curl -s $APP_URL/ | grep -o '<title>[^<]*</title>'
curl -s $APP_URL/ | grep -o '<link rel=canonical[^>]*>'
```

After the build log, the output is `<title>Storefront</title>`, then `<link rel=canonical href=https://storefront-x7k2m.sevalla.app/>` with your application's domain.

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


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