Skip to main content
A Gradio app runs on Sevalla as an application: Ingot, Sevalla’s builder, installs its dependencies from uv.lock, finds app.py and runs it with python app.py, after setting GRADIO_SERVER_NAME to 0.0.0.0 and GRADIO_SERVER_PORT to the port in the PORT environment variable. demo.launch() reads both, so the app listens where Sevalla sends traffic. The browser calls the app’s functions through Gradio’s queue, over server-sent events that Sevalla’s proxy passes through.

At a glance

Environment variables

Before you begin

  • A Sevalla company with a payment method, and a GitHub, GitLab or Bitbucket account for the repository. See Git providers.
  • Python 3.14 and uv 0.13 or later on your computer.

Create the project

Create the project with uv and add Gradio:
uv init writes pyproject.toml, a .python-version with 3.14, a .gitignore that keeps out .venv, and a Git repository. --no-package keeps the project a script rather than a package to install. uv add installs Gradio 6.31 into .venv and pins every package in uv.lock. The app replaces the main.py that uv init writes:
app.py
flagging_mode="never" removes the Flag button. Flagged examples go to .gradio/flagged in the app’s folder, and Sevalla resets an application’s files on every deployment, so they wouldn’t last. Run it with uv run app.py and open http://127.0.0.1:7860. Set Quantity to 3 and click Submit: Quote shows Total: $29.97. Press Ctrl+C to stop it.

Prepare the project for Sevalla

The project already has what Ingot needs: Ingot starts the web process with:
  • Gradio listens on all interfaces, on the port that Sevalla sets in PORT (8080 by default). Call demo.launch() without server_name or server_port: arguments to launch() win over the variables.
  • Don’t set share=True. It creates a temporary public link through Gradio’s own servers; on Sevalla, the application’s domain is the link. The runtime logs still print To create a public link, set share=True in launch(), which you can ignore.
To start the app another way, set the web process’s start command; see Set the start command. Commit everything and push it to your Git provider. uv init already created the repository:

Deploy to Sevalla

These steps build with Ingot. To build from your own Dockerfile instead, see 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.

Verify the deployment

  1. On the Deployments tab, click the deployment. Its Build log shows Ingot’s build plan: Python 3.14 from .python-version, uv from uv.lock, and Gradio with the start command for app.py.
    Build log
  2. Wait for the deployment’s status to change to Deployed. The application’s status next to its name changes to Running, and the web process’s runtime logs show * Running on local URL: http://0.0.0.0:8080.
  3. Click the domain under the application’s name, for example quote-tool-x7k2m.sevalla.app. Set Quantity to 3 and click Submit: Quote shows Total: $29.97.
  4. Call the same function from your computer with gradio_client, which comes with Gradio. Use your application’s domain:
    It prints Loaded as API: https://quote-tool-x7k2m.sevalla.app/, then Total: $29.97. Gradio names each function’s endpoint after the function, so quote is /quote.
  5. To check the deployment through the API, use APP_ID and DEPLOYMENT_ID from Deploy with the API. Get deployment (getDeploymentV3) returns success, and Get application runtime logs (getApplicationRuntimeLogsV3) finds Gradio’s start line:
    The first command prints success, and the second * Running on local URL: http://0.0.0.0:8080. The CLI has sevalla apps deployments get and sevalla apps logs runtime, and the MCP server get_deployment and search_runtime_logs.
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
If the deployment fails, read its build log, then see Troubleshoot Ingot builds. If it deploys but the page doesn’t load, read the application’s runtime logs.

Keep the web process at one instance

Gradio keeps its queue in the memory of the instance that runs it: a call joins the queue with one request, then reads its result from a second, long-lived request. Sevalla doesn’t keep a visitor’s requests on one instance, so with 2 or more instances a call whose second request reaches another instance fails, and its event stream reports 404: Not Found. Keep the web process at 1 instance, and choose a larger size when the app needs more CPU or memory. See Scaling.

Add a health check

Gradio takes a few seconds to import and start. Without a readiness probe, a new instance receives traffic as soon as its container starts, and requests in those seconds fail with 503. Point the probe at /, which answers once Gradio listens:
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 /. 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 reaches Deployed once the new instance passes the probe. See Health checks.

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 and a .dockerignore to the root of the repository:
Dockerfile
.dockerignore
Commit and push both files. Ingot doesn’t use the Dockerfile, so you can keep it in a repository that builds with Ingot, but it adds the .dockerignore patterns to its own: its build plan shows an Ignored row with 6 patterns from .dockerignore. 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 Update build strategy sheet with Dockerfile selected, the Dockerfile path, the Docker context and the Docker registry credentialThe Update build strategy sheet with Dockerfile selected, the Dockerfile path, the Docker context and the Docker registry credential
The build log shows 📦 Building and pushing docker image using Dockerfile... where Ingot’s build plan was. The app and gradio_client return Total: $29.97 as before, and the deployment’s Dockerfile tab shows your Dockerfile. See 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 instance. After you add a package with uv add, commit pyproject.toml and uv.lock together. See Deployments.

Use environment variables

Keep API keys and other secrets, such as a model provider’s key, in environment variables and read them with os.environ, for example os.environ["SALES_API_TOKEN"]. Add them on the application’s Environment variables tab, keep Available during runtime selected, and deploy: variables apply with the next deployment. Gradio reads its own settings from variables that start with GRADIO_. For example, GRADIO_ANALYTICS_ENABLED set to False turns off the usage analytics Gradio sends by default.

Add a custom domain

To serve the app from your own domain, such as quote.example.com, add the domain on the application’s Domains tab and create the DNS records that Sevalla shows. No code change is needed. Custom domains need a web process larger than H1, so scale the web process first. See Custom domains.

Deploy with the API

These calls make the same deployment as Deploy to Sevalla, in an order that an agent or a script runs as is. Each step names the API operation, then the CLI command and the MCP tool that do the same. The CLI reads the key from SEVALLA_API_TOKEN and prints tables; with --json it prints the API’s JSON, except that lists are bare arrays rather than the API’s data field. Before you start:
  • Put an API key in SEVALLA_API_KEY. The key needs the Company developer role or Company admin; see API keys. The commands use curl and jq.
  • Push the repository and connect its Git account to Sevalla, as in Before you begin. No API call reports whether the account is connected: if it isn’t, or Sevalla’s GitHub App can’t see the repository, creating the application fails with 400 and a message that starts with Cannot access repository https://github.com/acme/quote-tool: Repository not found or you don't have access. and says where to grant access.
  • Look up the location and the size. The first command picks the location by its region ID, here eu-frankfurt-1 (Frankfurt, Germany); see Locations for the others. List clusters (listClustersV3) and List process resource types (listProcessResourceTypesV3) return them; the CLI has sevalla resources clusters and sevalla resources process-types, and the MCP server get_platform_options.
If a variable ends up empty or null, run its curl command without jq: the response’s message says what went wrong.
1

Create the application

Create application (createApplicationV3). It creates the web process and doesn’t deploy:
CLI: sevalla apps create --name quote-tool --cluster "$CLUSTER_ID" --source privateGit --git-type github --repository https://github.com/acme/quote-tool --branch main. MCP: create_application with deploy set to false; by default it starts a deployment before the size and the probe are set.
2

Set the size and the readiness probe

The API creates the web process at S1, not the dashboard’s H1, and without health checks. List processes (listProcessesV3) finds the web process, and Update process (updateProcessV3) sets H1 and the readiness probe from Add a health check. Send every probe field, timeoutSeconds included: a probe set through the API without it waits up to 120 seconds for an answer, not the dashboard’s 1 second. The values are the dashboard’s defaults:
It prints {"size":"h1","readiness":"/","timeout":1}. The process keeps 1 instance, which Keep the web process at one instance explains. 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: sevalla_api_update with updateProcessV3 and the same body.
3

Deploy

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

Wait for the deployment

Get deployment (getDeploymentV3) until status is success or failed:
It prints success when the deployment finishes, or failed; after 30 minutes without either, it prints the status it last read. On failed, read the build log with Get application deployment logs (getApplicationDeploymentLogsV3), as in Verify the deployment. CLI: sevalla apps deployments get "$DEPLOYMENT_ID" --app-id "$APP_ID". MCP: get_deployment, then get_deployment_logs.
5

Turn on auto-deploy

Update application (updateApplicationV3):
It prints true. CLI: sevalla apps update "$APP_ID" --data '{"auto_deploy": true}'. MCP: sevalla_api_update with updateApplicationV3 and the same body.
List application domains (listApplicationDomainsV3) returns the domain to run the checks in Verify the deployment against:
It prints 200. To build from the Dockerfile instead, send {"build_type": "dockerfile", "dockerfile_path": "Dockerfile", "docker_context": "."} to Update application, then deploy and wait again. CLI: sevalla apps update "$APP_ID" --build-type dockerfile --dockerfile-path Dockerfile.