Skip to main content
A Dart Frog server runs on Sevalla as an application built from a Dockerfile in your Git repository: the official dart image generates the server with dart_frog build, compiles it ahead of time (AOT) into one native executable, and the web process runs that executable on Debian slim. Ingot, Sevalla’s default builder, has no Dart provider, so you choose the Dockerfile build strategy before the first deployment: with Ingot, the build stops with Ingot couldn't tell what kind of application this is. The server listens on the port that Sevalla sets in the PORT environment variable.

At a glance

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.
  • The Dart 3.13 SDK on your computer.

Create the project

Install the Dart Frog command-line tool, then create a project named storefront:
The project has one route, routes/index.dart, which answers every request to / with Welcome to Dart Frog!. dart_frog create also installs the dependencies, Dart Frog 1.2.6 among them, and writes their versions to pubspec.lock. Run dart_frog dev and open http://localhost:8080 to check it.

Prepare the project for Sevalla

Dart Frog’s .gitignore leaves pubspec.lock out of the repository. Delete the pubspec.lock line from .gitignore, so the lock file is committed and every build installs the versions you tested:
.gitignore
Add a custom entry point that stops the server when it receives SIGTERM:
main.dart
Dart Frog calls run from the server it generates, with the address and the port it listens on. See Shut down gracefully for why the server needs this file. The server needs no port configuration: the server that Dart Frog generates reads PORT, which Sevalla sets to the web process’s port (8080 by default), and listens on every IPv4 and IPv6 address.

Deploy with a Dockerfile

Ingot has no Dart provider, so Sevalla builds this application from a Dockerfile that you add to the repository. Add a Dockerfile and a .dockerignore to the root of the project:
Dockerfile
.dockerignore
The .dockerignore keeps the Git history, Dart’s and Dart Frog’s local folders, a local build folder, local environment files and logs out of the build. Build the image locally to check it:
The final image is about 128 MB, the executable 7.5 MB of it. Initialize a Git repository, commit everything and push it to your Git provider:

Deploy to Sevalla

These steps build from the Dockerfile in Deploy with a Dockerfile. A new application builds with Ingot, which can’t build a Dart project, so choose the Dockerfile build strategy before you deploy.
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

Click 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

Deploy

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

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.

Verify the deployment

  1. On the Deployments tab, click the deployment. Its Build log starts the build with 📦 Building and pushing docker image using Dockerfile..., and the dart compile exe step ends with Generated: /app/build/bin/server. The deployment’s Dockerfile tab shows the file the image was built from.
  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 Welcome to Dart Frog!
The application header with its name, Running status, repository, branch and the domain that opens the applicationThe application header with its name, Running status, repository, branch and the domain that opens the application
The application’s runtime logs show ✓ Running on http://:::8080: the server listens on port 8080 of every address. If the deployment fails, read its build log, then see Troubleshoot. To check the deployment from a terminal or an AI agent, read its status with Get deployment (getDeploymentV3) until it’s success, and its build log with Get application deployment logs (getApplicationDeploymentLogsV3), as in Deploy with the API. The build log names the Dockerfile build:
Then request the home page:
Get application runtime logs (getApplicationRuntimeLogsV3) with search finds the address the server listens on. The line starts with color codes for the check mark, which grep -o leaves out:

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. The server runs as process 1 in its container, and Linux ignores a signal that process 1 has no handler for. The server that Dart Frog generates installs none, so without main.dart it ignores SIGTERM and keeps running until Sevalla stops it 30 seconds later. With main.dart, the server stops taking new connections on SIGTERM, server.close() waits for the requests in progress to finish, and the process logs Server stopped and exits. That line ends the old instance’s runtime logs on every deployment after the first.

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 from the Dockerfile, then replaces the web process’s instances. When only your code changes, the build log shows CACHED for the steps up to COPY . ., so the build installs nothing again. When you add a package with dart pub add, commit pubspec.yaml and pubspec.lock with the code. See Deployments.

Use environment variables

Add configuration on the application’s Environment variables tab and read it with Platform.environment from dart:io, as the generated server reads PORT. Variables apply at the next deployment. Variables marked Available during buildtime arrive in the Docker build as build arguments, which a stage reads only after an ARG line for each one. See Environment variables.

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 the web process first. See Custom domains.

Troubleshoot

For more causes, see Troubleshoot builds and deployments.

Deploy with the API

These calls make the same deployment as Deploy to Sevalla, in an order that a script or an AI agent runs as it is. Each step names the Sevalla API operation, then the CLI command and the MCP server tool that do the same. You need:
  • An API key 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. 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 (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 lists them all:
CLI: sevalla resources clusters. MCP: get_platform_options.
2

Create the application

Create application (createApplicationV3) creates the application with a web process. It isn’t deployed yet:
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

Choose the Dockerfile build strategy

The application builds with Ingot (build_type is ingot), which can’t build a Dart project. Update application (updateApplicationV3) switches it to the Dockerfile at the root of the repository:
CLI: sevalla apps update $APP_ID --data '{"build_type":"dockerfile","dockerfile_path":"Dockerfile","docker_context":"."}'. MCP: sevalla_api_update with updateApplicationV3 and the same body.
4

Find the domain

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:
CLI: sevalla apps domains list --app-id $APP_ID. MCP: get_application.
5

Find the web process

List processes (listProcessesV3) returns the web process that the application was created with:
CLI: sevalla apps processes list --app-id $APP_ID. MCP: get_application.
6

Find the H1 size

List process resource types (listProcessResourceTypesV3) returns the sizes by name, in lowercase:
CLI: sevalla resources process-types. MCP: get_platform_options.
7

Set the size

The API creates the web process at S1, where the dashboard’s default is H1. Update process (updateProcessV3) sets the size:
CLI: sevalla apps processes update $WEB_ID --app-id $APP_ID --resource-type $H1_ID. MCP: scale_process with size_id.
8

Turn on auto-deploy

Update application (updateApplicationV3) turns on automatic deployments for every push to the branch:
CLI: sevalla apps update $APP_ID --data '{"auto_deploy":true}'. MCP: sevalla_api_update with updateApplicationV3.
9

Deploy

Trigger deployment (triggerDeploymentV3) deploys the latest commit on the branch:
CLI: sevalla apps deployments trigger $APP_ID --branch main. MCP: trigger_deployment.
10

Wait for the deployment

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. The first build takes about a minute:
CLI: sevalla apps deployments get $DEPLOYMENT_ID --app-id $APP_ID. MCP: get_deployment.
11

Read the build log

Get application deployment logs (getApplicationDeploymentLogsV3) returns the build log, oldest line first: the checkout, the Docker build and the rollout. When the status is failed, the last lines say why. Without limit, it returns the latest 1,000 lines:
CLI: sevalla apps deployments logs $DEPLOYMENT_ID --app-id $APP_ID --limit 5000. MCP: get_deployment_logs.
12

Check the application

Request the home page from the application’s domain:
Then run the other checks in Verify the deployment.