# Applications - Analytics
Source: https://docs.sevalla.com/applications/analytics
View detailed analytics for your applications, including usage and performance insights.
Sevalla charges for [Application Hosting](https://sevalla.com/application-hosting/) based on bandwidth, build time, and application hosting pod usage. With Application Analytics, you can get insights into your application's usage data. For more information about how we calculate your invoice, refer to [Application Pricing](/billing/application-pricing).
The application billing amounts are also included in the **Spending overview** chart on your Sevalla Dashboard. This chart shows the spending overview for all Sevalla services.
## Application analytics
Each application's analytics is broken down into:
* **Compute:** The resources you use for your application.
* **Web:** Information about the requests to your application.
When viewing the application analytics, you can choose to see data for the past 1 hour, 6 hours, 12 hours, 1 day, 2 days, 4 days, 7 days, 14 days, or 30 days, or select a specific date and time period. You can refresh the chart data at any time.
When you hover over a chart, a corresponding reference line appears on the other charts on the same page. You can click and drag this reference line to zoom into a specific time period, and all charts on the page will update to show that same time range.
To access these in-depth reports, go to your application's **Analytics** page (**Applications** > ***appname*** > **Analytics**).
### Compute
Using the dropdown within Compute, you can view the information for your web process, a background worker, or a cron job. Select **Show limit** to compare your usage with your current plan limit.
#### Memory usage
The Memory usage chart shows the average of the total memory (RAM) used for the selected time period. If a process uses most or all of the memory available, we recommend upgrading to an [application hosting pod](/billing/application-pricing) with more available memory.
#### CPU usage
In the CPU usage chart, you can see the average of the total CPU utilization for the selected time period, expressed as a percentage of the instance's CPU resources. If you see a high percentage of CPU usage (near 100%), we recommend upgrading to an [application hosting pod](/billing/application-pricing) with more CPU for that process. If your application is stateless (no [persistent storage](/applications/storage)), you also have the option to enable [automatic horizontal scaling](/applications/scalability) for the **web process**. This lets you set a minimum and maximum number of instances (up to 10) that the process can scale between as needed.
#### Instance count
The Instance count chart shows the number of instances in use for the selected process and time period. Select **Show limit** to compare your usage to your process resource limit. You can adjust the number of instances for your process within **Processes**, click the kebab (three dots) on the required process, and select **Update process**.
### Web
You can filter the web charts using **Add filter**. This filters all of the charts on the **Web** page. The following options are available:
* Source IP
* Country
* Device type
* HTTP method
* Path
* User agent
* HTTP version
* Status code
#### Requests volume by country
The Requests volume by country chart displays the number of requests, ranked by the country from which they originated. You can zoom in and out of the map, and hover over a country to see the exact number of requests from that location. You can also filter the chart to include or exclude specific countries.
#### Requests per minute
The Requests per minute chart shows the average requests per minute (RPM) of all HTTP requests for the time period selected.
#### Bandwidth
The Bandwidth chart shows your bandwidth usage over the selected timeframe.
#### Response time
The Response time chart shows the average response time for all HTTP requests for the time period selected.
#### Status codes
The Status codes chart displays the total number of each status code returned for requests. This is useful for analyzing your site to identify when requests return codes other than 200.
#### Slowest requests
The slowest requests table shows the 10 slowest requests to your application for the selected time period and the average response time it took to complete.
#### Top pages
The Top pages table shows the top 10 most requested pages by the number of views for your application.
## Additional notes
Analytics data is retained for 30 days. We suggest checking your **Application Analytics** frequently after first deploying to Sevalla and periodically after that. If you see any unexplained analytics data or inconsistencies that concern you, [let our Support team know](/support/contact-support/), and we can further investigate to help determine the cause.
# Buildpacks
Source: https://docs.sevalla.com/applications/build-options/buildpacks
Learn how to use buildpacks to automate your application builds.
Sevalla uses [Nixpacks](/applications/build-options/nixpacks) by default to build your application and set up the container image. Sevalla also offers Buildpacks, an open-source project maintained by Heroku, as one of the options to automatically determine and create a container for your application based on your repository. Buildpacks are scripts that are run when your application is deployed to install dependencies for your application and configure your environment.
You can choose Buildpacks by changing the **Build environment** option in [application settings](/applications/settings/) (**Settings** > **Build strategy** > **Update build strategy**).
You can choose which [Heroku builder](https://github.com/heroku/cnb-builder-images) to use for your application. It is your responsibility to ensure this is compatible with your application by checking the Buildpacks and Builder changelogs for your application's language.
## Supported languages
We support the following application languages for Buildpacks:
* Node.js
* Ruby
* Python
* Java
* Scala
* PHP
* Go
If you do not specify a version in your application’s code, the buildpack uses the latest available version.
If you want to use a different language version for your application, you’ll need to [set the version in your application’s files](#set-a-buildpacks-language-version).
If you want to use a language that is not a supported Buildpack language, you can first check to see if it’s a supported language with [Nixpacks](/applications/build-options/nixpacks) or [Railpack](/applications/build-options/railpack). If it isn’t, you must use a [Dockerfile](/applications/build-options/dockerfile).
## Configure Buildpacks
Some applications require no configuration, but some require specialized commands and options to run, such as:
[Environment variables](/applications/environment-variables) — You may need to set certain environment variables to run your application.
[Processes](/applications/processes) — Sevalla can automatically detect your web process command. You can change this if required, and you can define additional processes.
[Processes in a Procfile](/applications/processes#defining-processes-in-a-procfile) — You may want to define your processes in a Procfile within your application’s code.
## Add or edit Buildpacks
You can manage buildpacks on your [**application’s Settings page**](/applications/settings/). You can add additional build packs within **Build strategy** > **Update build strategy** > **Add buildpack**.
When you add a buildpack, it’s automatically added to the end of the buildpacks list, so you may need to edit the order of your buildpacks. You can drag and drop the buildpacks to change their order, or remove buildpacks within **Build strategy** > **Update build strategy**.
The buildpack containing your application's primary language must be the last one in the buildpacks list. For example, if you have a Node.js application and need to add another buildpack, make sure the Node.js buildpack is at the end of the list.
## Buildpack binary directories
With buildpacks, the binary directories may differ from the default binary directories for the application language. The following table shows the binary directories used for each buildpack language:
| Language | Directory |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Node.js | **/layers/heroku\_nodejs-engine/dist/bin/node** |
| Ruby | **/usr/bin/ruby** |
| Python | **/usr/bin/python** |
| Java | **/layers/heroku\_jvm/openjdk/bin/java** |
| Scala | Scala doesn’t have a specific default binary path like some other compiled languages. When you compile a Scala program, it generates bytecode that runs on the Java Virtual Machine (JVM).
The compiled Scala classes are typically stored in a directory structure that mirrors the package structure of your code. This is similar to how Java classes are organized. By default, when you compile a Scala source file, the compiled .class files will be placed in the same directory as the source code (within a subdirectory structure based on the package declarations).
If needed, you can install Scala’s runtime tools using a Dockerfile instead of a buildpack.
|
| PHP | **/workspace/.heroku/php/bin/** |
| Go | Go doesn’t have a specific default binary path like some other compiled languages. When you compile a Go program, the resulting binary executable is typically placed in the same directory as your source code by default. If needed, you can install Go’s runtime tools using a Dockerfile instead of a buildpack.
|
## Set a Buildpack’s language version
When you select the option to use Buildpacks, if you do not specify a version in your application’s code, the Buildpack will use the latest available version. If you want to use a different language version for your application, you’ll need to set the version in your application’s files.
The method for setting the version varies by language. Below we’ve included examples for currently supported languages.
### Go
To specify your Go version, include the following in your application’s **go.mod** file:
```text theme={null}
// +heroku goVersion go1.11
go 1.21.1
```
### Java
To specify your Java version, include the following in your application’s **system.properties** file:
```text theme={null}
java.runtime.version=11
```
### Node.js
To specify your Node.js and npm versions, include the following in your application’s **package.json** file:
```text theme={null}
"engines": {
"node": "^16.14.0",
"npm": "^8.3.1"
}
```
Specifying the npm version isn’t usually necessary (npm is bundled with Node.js). Setting the npm version is only needed when you want to use a different version than the one bundled with your version of Node.js
#### React
If you’re using React and want to specify your React version, replace or add the React version in the `dependencies` section of your **package.json** file:
```text theme={null}
"react": "^17.0.2"
```
To also set the Node.js and npm versions in your React application, include the following in your application’s **package.json** file:
```text theme={null}
"engines": {
"node": "^16.14.0",
"npm": "^8.3.1"
}
```
### PHP
Buildpacks support the currently supported PHP versions; once a PHP version reaches end-of-life, it is no longer supported but remains available so you can upgrade your application to a newer version.
To specify your PHP version, include the following in your application’s **composer.json** file:
```text theme={null}
{
"require": {
"php": "~8.1.0"
}
}
```
#### PHP.ini
You can change PHP.ini settings using a `.user.ini` file in the same directory as the `.php` file. For more information about which settings you can control, refer to the [PHP manual](https://www.php.net/manual/en/configuration.file.per-user).
A small set of `PHP.ini` configuration directives cannot be modified using `.user.ini`; for example, `PHP_INI_SYSTEM`. In this case, you must pass additional configuration settings for PHP at startup time using a custom configuration file `fpm_custom.conf` with the `php_value` and `php_flag` directives.
If you use a custom configuration file, you must tell your application to start with this configuration by adding `-F` to the start command. You can also use this configuration file to modify the [PHP-FPM behavior](https://www.php.net/manual/en/install.fpm.configuration.php).
### Python
To specify your Python version, include the following in your application’s **runtime.txt** file:
```text theme={null}
python-3.10.13
```
You can also specify module versions within the **requirements.txt** file:
```text theme={null}
Django==4.1
virtualenv==20.18.0
```
### Ruby
To specify your Ruby version, include the following in your **Gemfile**:
```text theme={null}
ruby "3.0.6"
```
### Scala
To specify your Scala version, include the following in your application’s **build.sbt** file:
```text theme={null}
scalaVersion := "3.2.2"
```
# Dockerfile
Source: https://docs.sevalla.com/applications/build-options/dockerfile
Find out how to use Dockerfiles to customize your application builds.
Sevalla uses [Nixpacks](/applications/build-options/nixpacks) by default to build your application and set up the container image. You can change this to use a Dockerfile to set up your container image within the application's [Settings](/applications/settings/) (**Settings** > **Build strategy** > **Update build strategy**). Using a Dockerfile gives you more control, and you can use almost any language, so you are not restricted to the languages [Nixpacks](/applications/build-options/nixpacks), [Railpack](/applications/build-options/railpack), or [Buildpacks](/applications/build-options/buildpacks) support.
A Dockerfile sets up the environment depending on the instructions within the Dockerfile, which must include commands to install the language, adjacent software, and libraries, [set up the port](/applications/networking#edit-application-port), and start the web server. Sevalla automatically sets the `PORT` environment variable. You do not need to define it yourself or hard-code it into the application. For example, in Node.js, use `process.env.PORT` in your code when referring to the server port.
Detailed information about how to create a Dockerfile is available in [Docker Docs](https://docs.docker.com/compose/gettingstarted/#step-2-create-a-dockerfile).
To use the Web Terminal with an application created with a Dockerfile, make sure Bash is installed in the container. In most cases, the base image (e.g. Ubuntu) includes a shell package and will work by default. In some more streamlined containers, the shell package may not be included, and you’ll need to add it. The base image determines how to add the shell package:Alpine: apk add bashUbuntu/Debian: apt install bashFedora: dnf install bash
## Dockerfile settings
To use a Dockerfile, you must change the **Build strategy** in the application's [Settings](/applications/settings/) (**Settings** > **Build strategy** > **Update build strategy**).
The **Dockerfile path** is the path to your Dockerfile relative to the repository root. For example, if your Dockerfile is in the repository root, enter **Dockerfile** in that field. If your Dockerfile is in a subdirectory named **app**, enter the path to the Dockerfile: **app/Dockerfile**.
**Context** is the path in the repository we need access to so we can build your application. Most applications are built from the repository root, and you can enter the repository root (**.**) in the **Context** field. If your application needs to be built from a subdirectory (e.g., **app**), enter that subdirectory path in the **Context** field: **app**.
The **Registry credential** is only required for private Docker images. You must enter your registry credentials within **Integration** > **Registry credentials**. Once you’ve entered your credentials in the Company settings, you can choose which credentials you want to use.
## Dockerfile and pnpm
If you use [pnpm with a Dockerfile](https://pnpm.io/docker), you must use the following location for `PNPM_HOME`:
```text theme={null}
ENV PNPM_HOME="~/.pnpm"
```
## Example Dockerfile
To help get you started, here’s an example Dockerfile you can use for reference or as a starting point.
```text theme={null}
FROM node:carbon
LABEL maintainer="Sevalla devs"
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
COPY . /app
# Install any needed packages specified in package.json
RUN npm install
# Run app when the container launches
CMD ["npm", "start"]
```
## Host a database with a Dockerfile
If you combine [persistent storage](/applications/storage) and a Dockerfile, you can host pretty much any database you want with our [Application Hosting](https://sevalla.com/application-hosting/). Even something like a Microsoft SQL Server database, which isn’t supported on our [Database Hosting](https://sevalla.com/database-hosting/), can be deployed. If you can containerize it with a Dockerfile, you can deploy it on Application Hosting.
Persistent storage is needed to retain the data in your database. If you deploy a database on Application Hosting without persistent storage, all data will be lost if the application is restarted or redeployed.
Docker images for many databases can be found at [Docker Hub](https://hub.docker.com/). Look for the [Docker Official Image](https://docs.docker.com/docker-hub/image-library/trusted-content/) badge when searching for a database to get the most secure and well-documented images that follow best practices.
# Nixpacks
Source: https://docs.sevalla.com/applications/build-options/nixpacks
Explore building applications with Nixpacks for flexible and reproducible builds.
Sevalla uses Nixpacks, an open-source project maintained by Railway, to automatically create your application’s container image based on your repository. Nixpacks are scripts that are run when your application is deployed to install dependencies for your application and configure your environment. Nixpacks uses fewer resources and supports 20+ languages.
If you currently use [Railpack](/applications/build-options/railpack), [Buildpacks](/applications/build-options/buildpacks), or a [Dockerfile](/applications/build-options/dockerfile), you can change this to Nixpacks within the **Build strategy** option in [application settings](/applications/settings/) (**Settings** > **Build strategy** > **Update build strategy**).
[Railpack](/applications/build-options/railpack), the successor to Nixpacks from the Railway team, is also available as a build type.
New applications within Sevalla always use the latest recommended Nixpacks. Sometimes, this may cause changes to the build process; it is your responsibility to keep up-to-date with the latest changes by checking the [Nixpacks changelogs](https://github.com/railwayapp/nixpacks/releases) for your application’s language. You can check and change the Nixpacks version your application uses within **Settings** > **Build strategy** > **Update build strategy**.
## Supported languages
Nixpacks supports the following languages:
* Clojure
* Cobol
* Crystal
* C#/.NET
* Dart
* Deno
* Elixir
* F#
* Go
* Haskell
* Java
* Lunatic
* Node.js
* PHP
* Python
* Rust
* Swift
* Scala
* Zig
If you do not specify a version in your application’s code, Nixpacks will use the current default version. If you have a PHP application with a composer.json file in the repository, it must include a require key with a PHP version. For more details on how to specify the PHP version, see Set a Nixpack’s Language Version below.
To use a different language version, [set the version in your application’s files](#set-a-nixpacks-language-version).
When using Nixpacks, there usually isn’t a need to choose or add different providers for the build because they are automatically detected. If additional providers are needed for the application, you can define those in a [Nixpacks configuration file](https://nixpacks.com/docs/guides/configuring-builds).
If you want to use a language that is not a supported Nixpacks or [Buildpacks](/applications/build-options/buildpacks) language, you must use a [Dockerfile](/applications/build-options/dockerfile). You can change this within **Settings** > **Build strategy** > **Update build strategy**.
## Configure Nixpacks
Some applications require no configuration, but some require specialized commands and options to run, such as:
[Environment variables](/applications/environment-variables) — You may need to set certain environment variables to run your application.
[Processes](/applications/processes) — Sevalla can automatically detect your web process command. You can change this if required, and you can define additional processes.
[Processes in a Procfile](/applications/processes#defining-processes-in-a-procfile) — You may want to define your processes in a Procfile within your application’s code.
## Configure builds
By adding a `nixpacks.toml` file to your repository, you can customize the final Docker image generated by Nixpacks. This configuration file allows you to specify additional providers, install extra packages, customize your build commands, override the start command, and even define new build phases, giving you greater control over the build process and the resulting image.
For more information about how to configure the `nixpacks.toml` file, refer to [Nixpack's documentation](https://nixpacks.com/docs/guides/configuring-builds).
### Nixpacks and pnpm
If you use pnpm with Nixpacks, you must use the following location for `PNPM_HOME`:
```
ENV PNPM_HOME="/app/.pnpm"
```
## Nixpacks binary directories
With Nixpacks, the binary directories may differ from the default binary directories for the application language. The following table shows the binary directories used for some of the most common languages:
| Language | Directory |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Node.js | **/nix/var/nix/profiles/default/bin/node** |
| Ruby | **/nix/var/nix/profiles/default/bin/ruby** |
| Python | **/nix/var/nix/profiles/default/bin/python** |
| Java | **/nix/var/nix/profiles/default/bin/java** |
| Scala | Scala doesn’t have a specific default binary path like some other compiled languages. When you compile a Scala program, it generates bytecode that runs on the Java Virtual Machine (JVM). The compiled Scala classes are typically stored in a directory structure that mirrors the package structure of your code. This is similar to how Java classes are organized. By default, when you compile a Scala source file, the compiled .class files will be placed in the same directory as the source code (within a subdirectory structure based on the package declarations).
If needed, you can install Scala’s runtime tools using a Dockerfile instead of using a Nixpack.
|
| PHP | **/nix/var/nix/profiles/default/bin/php** |
| Go | Go doesn’t have a specific default binary path like some other compiled languages. When you compile a Go program, the resulting binary executable is typically placed in the same directory as your source code by default. If needed, you can install Go’s runtime tools using a Dockerfile instead of using a Nixpack.
|
## Set a Nixpack’s language version
When you use Nixpacks, if you do not specify a version in your application’s code, the Nixpack will use the latest available version. If you want to use a different language version for your application, you’ll need to set the version in your application’s files or, depending on the language, with an [environment variable](/applications/environment-variables).
The available methods for setting the version vary by language. Below, we’ve included examples for the most common languages.
### Go
To specify your Go version, include the following in your application’s **go.mod** file:
```
go 1.18
```
### Java
To specify your Java version, set the `NIXPACKS_JDK_VERSION` [environment variable](/applications/environment-variables) and make sure the variable is available during the build process.
If you’re using Gradle, to specify the version, set the `NIXPACKS_GRADLE_VERSION` [environment variable](/applications/environment-variables) and make sure the variable is available during the build process.
### Node.js
To specify your Node.js version, do one of the following:
Include the following in your application’s package.json file:
```
"engines": {
"node": "18"
}
```
Or, set the `NIXPACKS_NODE_VERSION` [environment variable](/applications/environment-variables) and make sure the variable is available during the build process.
Only the major version like 14 or 14.x can be specified. The latest release under that major version will be used.
### PHP
Nixpacks only supports PHP version 8.1 or higher
To specify your PHP version, include the following in your application’s **composer.json** file:
```
{
"require": {
"php": "8.2"
}
}
```
### Python
To specify your Python version, do one of the following:
* Include the following in your application’s **runtime.txt** file: `python-3.10.6`
* Include the following in a .python-version file in your repository: `3.10.6`
* Set the `NIXPACKS_PYTHON_VERSION` [environment variable](/applications/environment-variables) and make sure the variable is available during the build process.
### Ruby
To specify your Ruby version, include the version in a **.ruby-version** file in your application, for example:
```
3.0.6
```
### Scala
To specify your Scala version, include the following in your application’s **build.sbt** file:
```
scalaVersion := "3.2.2"
```
# Railpack
Source: https://docs.sevalla.com/applications/build-options/railpack
Build your applications with Railpack, the zero-configuration successor to Nixpacks.
Sevalla offers Railpack, an open-source project maintained by Railway and the successor to [Nixpacks](/applications/build-options/nixpacks), to automatically create your application's container image based on your repository. Railpack analyzes your repository and builds an optimized container image with zero configuration, powered by [BuildKit](https://docs.docker.com/build/buildkit/).
[Nixpacks](/applications/build-options/nixpacks) remains the default build type for new applications.
If you currently use [Nixpacks](/applications/build-options/nixpacks), [Buildpacks](/applications/build-options/buildpacks), or a [Dockerfile](/applications/build-options/dockerfile), you can change this to Railpack within the **Build strategy** option in [application settings](/applications/settings/) (**Settings** > **Build strategy** > **Update build strategy**). Railpack is also available through the public API by setting `build_type` to `railpack`.
## Supported languages
Railpack detects your application's language based on the files in your repository (for example, `package.json` for Node.js, `go.mod` for Go, or `composer.json` for PHP) and builds the following out of the box:
* Node.js
* Python
* Go
* PHP
* Java
* Ruby
* .NET
* Deno
* Rust
* Elixir
If you want to use a language that Railpack does not support, check whether it is supported by [Nixpacks](/applications/build-options/nixpacks) or [Buildpacks](/applications/build-options/buildpacks). If it isn't, you must use a [Dockerfile](/applications/build-options/dockerfile). You can change this within **Settings** > **Build strategy** > **Update build strategy**.
## Configure Railpack
Some applications require no configuration, but some require specialized commands and options to run, such as:
[Environment variables](/applications/environment-variables) - You may need to set certain environment variables to run your application.
[Processes](/applications/processes) - Sevalla can automatically detect your web process command. You can change this if required, and you can define additional processes.
## Start command
Custom start commands work the same way as with other build types: if your web process has a start command set, it overrides the one Railpack detects. You can change your web process's start command on the [Processes page](/applications/processes).
## Configure builds
By adding a `railpack.json` file to the root of your repository, you can customize the final image generated by Railpack. This configuration file allows you to install extra packages, define custom build steps and commands, configure caches, and override the deploy settings, giving you greater control over the build process and the resulting image. For example:
```json theme={null}
{
"$schema": "https://schema.railpack.com",
"steps": {
"install": {
"commands": ["npm install"]
},
"build": {
"inputs": [{ "step": "install" }],
"commands": ["...", "./my-custom-build.sh"]
}
},
"deploy": {
"startCommand": "node dist/index.js"
}
}
```
While you can override the start command with `railpack.json` or the `RAILPACK_START_CMD` environment variable, the preferred way is to set the start command for your web process on the [Processes page](/applications/processes). A start command set there always takes precedence.
Reference the schema at `https://schema.railpack.com` in your `railpack.json` file to get autocomplete and validation in your editor. For all available options, refer to the [Railpack configuration documentation](https://railpack.com/config/file).
### Build configuration with environment variables
You can also customize the build with [environment variables](/applications/environment-variables). Make sure the variables are available during the build process.
| Variable | Description |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `RAILPACK_INSTALL_CMD` | Override the command run in the install step. |
| `RAILPACK_BUILD_CMD` | Override the command run in the build step. |
| `RAILPACK_START_CMD` | Override the command run when the container starts. |
| `RAILPACK_PACKAGES` | Install additional [Mise](https://mise.jdx.dev/) packages in the format `pkg@version`, separated by spaces. |
| `RAILPACK_BUILD_APT_PACKAGES` | Install additional apt packages during the build, separated by spaces. |
| `RAILPACK_DEPLOY_APT_PACKAGES` | Install additional apt packages in the final image, separated by spaces. |
For the full list of options, refer to the [Railpack environment variable documentation](https://railpack.com/config/environment-variables).
## Set a Railpack language version
If you do not specify a version in your application's code, Railpack uses its current default version for the language. To use a specific version, set it in your application's files or with an [environment variable](/applications/environment-variables). When you use an environment variable, make sure the variable is available during the build process.
Railpack also reads [Mise](https://mise.jdx.dev/)-compatible version files, such as `.tool-versions` and `mise.toml`, for most languages.
### Deno
To specify your Deno version, include the version in a `.deno-version` file in your repository, or set the `RAILPACK_DENO_VERSION` environment variable.
### Elixir
To specify your Elixir version, include the version in a `.elixir-version` file in your repository, set it in your `mix.exs` file, or set the `RAILPACK_ELIXIR_VERSION` environment variable.
The Erlang/OTP version is detected automatically from the Elixir version. To override it, include the version in a `.erlang-version` file, or set the `RAILPACK_ERLANG_VERSION` environment variable.
### Go
To specify your Go version, include the following in your application's **go.mod** file:
```
go 1.23
```
Or, set the `RAILPACK_GO_VERSION` environment variable.
### Java
To specify your Java version, set the `RAILPACK_JDK_VERSION` environment variable.
If you're using Gradle, to specify the Gradle version, set the `RAILPACK_GRADLE_VERSION` environment variable.
### .NET
To specify your .NET version, set the `TargetFramework` in your project's **.csproj** file, include the version in your **global.json** file, or set the `RAILPACK_DOTNET_VERSION` environment variable.
### Node.js
To specify your Node.js version, do one of the following:
Include the following in your application's **package.json** file:
```
"engines": {
"node": "22"
}
```
Or, include the version in a **.nvmrc** or **.node-version** file in your repository, or set the `RAILPACK_NODE_VERSION` environment variable.
Railpack supports npm, pnpm, yarn, and Bun, detected from the `packageManager` field in **package.json** or your lock file. If you use Bun, you can specify the Bun version with the `engines.bun` field in **package.json**, a **.bun-version** file, or the `RAILPACK_BUN_VERSION` environment variable.
### PHP
Railpack only supports PHP version 8.2 or higher.
To specify your PHP version, include the following in your application's **composer.json** file:
```json theme={null}
{
"require": {
"php": "8.4"
}
}
```
To install additional PHP extensions, set the `RAILPACK_PHP_EXTENSIONS` environment variable to a comma-separated list, for example `gd,imagick,redis`.
### Python
To specify your Python version, do one of the following:
* Include the version in a **.python-version** file in your repository: `3.13`
* Include the version in a **runtime.txt** file.
* Set the `RAILPACK_PYTHON_VERSION` environment variable.
Railpack supports pip, poetry, pdm, uv, and pipenv, detected from your dependency files.
### Ruby
To specify your Ruby version, include the version in a **.ruby-version** file in your repository, set it in your **Gemfile** (for example, `ruby "3.4.6"`), or set the `RAILPACK_RUBY_VERSION` environment variable.
### Rust
To specify your Rust version, set the `channel` in your **rust-toolchain.toml** file, set `rust-version` in your **Cargo.toml** file, include the version in a **.rust-version** file, or set the `RAILPACK_RUST_VERSION` environment variable.
For more details about how Railpack builds each language, refer to the [Railpack documentation](https://railpack.com/).
# CDN
Source: https://docs.sevalla.com/applications/cdn
Set up and manage your content delivery network for faster app performance.
A content delivery network (CDN) is a crucial component of a modern hosting stack. We're proud to offer a premium CDN powered by Cloudflare for Sevalla's Application Hosting at no additional cost.
Our free Cloudflare integration secures your applications hosted on Sevalla. In addition to an enterprise-level firewall and DDoS protection, Sevalla customers also have access to a high-performance HTTP/3 CDN powered by Cloudflare's robust global network.
With a network that spans 260+ cities in more than 100 countries, Cloudflare operates one of the largest CDN networks in the world. This means your application will be able to serve static assets from many more locations without the need to pay for additional services.
Sevalla's CDN is **not** enabled by default on Application Hosting. The application's **Overview** page shows if the CDN is enabled or disabled.
## Enable or disable Sevalla's CDN
To enable the CDN within Sevalla, click **Applications** > **app name** > **Networking**, and within **CDN & Edge caching**, click **Update settings**.
To enable the CDN, select **CDN**.
You can also enable or disable the CDN by sending a `POST` request with the [CDN API endpoint](https://api-docs.sevalla.com/v3/applications/toggle-cdn). To access and use the API with your account, you need to generate an API Key under **Integration** > **API keys**.
To use the CDN API endpoint, you need your application's unique ID. You can obtain this programmatically by listing all applications associated with your Sevalla company with the [applications endpoint](https://api-docs.sevalla.com/v3/applications/list-applications), which provides essential details about each application.
## File types cached by Sevalla's CDN
Files are cached based on the file extension, not the MIME type. We **do not** cache requests or responses containing the `Authorization` header.
| 7z | afm | apk | avi | avif | bmp | bz2 | cff |
| :---- | :----- | :--- | :-- | :--- | :--- | :--- | :--- |
| css | cur | data | dmg | doc | docx | eot | epub |
| exe | ffil | flac | flv | gif | glb | gz | heic |
| heif | ico | img | iso | jfif | jpeg | jpg | js |
| json | lottie | lwfn | m4a | m4v | map | md | mid |
| midi | mkv | mov | mp3 | mp4 | mpga | odp | ods |
| odt | ogg | ogv | otf | pdf | pfb | pfm | png |
| ppt | pptx | pro | qt | rar | rtf | scss | std |
| svg | svgz | tar | tgz | tif | tiff | ts | ttf |
| txt | usdz | wasm | wav | webm | webp | wmv | woff |
| woff2 | xls | xlsx | xml | xsf | zip | zst | |
## Clear the CDN cache
Sevalla automatically purges the CDN cache after every successful deploy, so updated content is served without any manual action in most cases.
To clear the CDN cache, within Sevalla, click **Applications** > **app name** > **Networking**, and within **CDN & Edge caching**, click **Purge cache**. If both CDN and edge caching are enabled, purging the cache will apply to both.
You can also clear the CDN cache by sending a `POST` request with the [clear-cache API endpoint](https://api-docs.sevalla.com/v3/applications/purge-edge-cache). If you have enabled [Edge Caching](/applications/edge-caching/), this also clears the Edge Cache.
Clearing the CDN Cache in all of Cloudflare's data centers may take 2-5 minutes to fully complete.
# Applications - Deployments
Source: https://docs.sevalla.com/applications/deployments
Track and manage your application deployments with real-time updates.
You can manually deploy your application from the **Deployments**, view your application’s deployment history, and view the deployment changes.
## Deploy your application
If automatic deployment is enabled, the application deploys every time a commit is made to the branch in the Git repository. You can enable or disable automatic deployments for private Git repositories [**in the application’s Settings**](/applications/settings/).
To manually deploy your application, click **Deploy now**, select the branch you want to deploy, and click **Deploy**.
If you want to restart your application without rebuilding it, select **Skip building (restart latest)** and click **Deploy**.
## Zero downtime with health checks
If your application includes a health check and you have defined the health check path within the [web process](/applications/processes#web-process), there is zero downtime between deployments. When the application deploys or redeploys, or if the pod restarts, the old pods continue to run until the new pods are ready.
You can enable a readiness probe to check if the process is ready to receive traffic; if this fails, the process won't serve requests until it is healthy. You can also enable a liveliness probe to check if the process is still running correctly; if this fails, the process automatically restarts.
Implementing health checks for production applications is **strongly recommended** to minimize downtime during deployments and ensure system reliability. Health checks continuously monitor the application’s status, ensuring it remains functional during updates and enabling workloads to be quickly rescheduled at any time, such as during maintenance or unexpected disruptions. This proactive approach helps maintain application stability and delivers a seamless user experience.
Zero downtime deployments cannot currently be guaranteed for applications with [persistent disk storage](/applications/storage) attached. If it is an option for your use case, we highly recommend using [object storage](/object-storage) instead of a persistent disk.
## Individual deployment details
If you click on any of the previous deployments, you’ll be brought to a dedicated page that shows the deployment log and details for that specific deployment. If the deployment fails, check the deployment log to determine where the process may have encountered an error.
## Deployment logs
When you deploy your application to Sevalla, the deployment log shows each step of the deployment and whether it is successful or not. For example, an application using Nixpacks shows the following steps in the deployment log:
1. Fetching source code from GitHub.
2. Source code fetched successfully.
3. Building docker image using Nixpacks.
4. Docker image built successfully.
5. Pushing Docker image to registry.
6. Docker image pushed successfully.
7. Starting rollout.
8. App has been deployed successfully.
You can also see the **Build environment** and **Build path**. To change the build environment to use [Railpack](/applications/build-options/railpack), [Buildpacks](/applications/build-options/buildpacks), or a [Dockerfile](/applications/build-options/dockerfile), click **Update build strategy**. If the deployment fails at any stage, the logs display an error message indicating the reason for the failure. For information on troubleshooting errors, refer to [Failed Deployment](/applications/troubleshooting/failed-deployment/).
Deployment logs are stored for up to 30 days.
#### Runtime logs
If the deployment is successful, the runtime logs are shown for the deployment. If the deployment is successful but the application fails to run, the runtime logs may show the underlying reason for this.
#### Deployment details
For Git repositories, this shows information such as:
* The name of the Git repository and branch.
* The Commit ID, with a link to the commit at the Git service provider.
* Who initiated the deployment.
* The deployment start date and time.
* The time it takes for the deployment to finish (**Deploy time**).
* The deployment type is either manual or automatic. Automatic deployments only occur if you have selected **Automatic deployment on commit**.
* The [data center location](/service-information/data-center-locations/).
* The commit message.
You can adjust the resource settings, including CPU and RAM allocation for the build process, within the application’s [Settings](/applications/settings/).
For Docker images, this shows information such as:
* The path to the Docker image.
* The deployment start date and time.
* The deployment type.
* The [data center location](/service-information/data-center-locations/).
## Cancel a deployment
There may be times when you need to cancel a deployment of your application. You may want to change the code, or perhaps the deployment is taking longer than expected, and you want to investigate your application’s code.
To cancel a deployment, click **Cancel** on the **Deployment is in progress** notification.
You may still incur costs for the build time when you cancel a deployment.
## View the deployment changes
Within each individual deployment, you can view the **Changeset**, which displays the changes made to both the runtime and build.
# Docker images
Source: https://docs.sevalla.com/applications/docker-images
Manage your Docker images and learn how to use them for deployments.
When you add an application, you can choose to use a [Git repository](/applications/git/overview) or a Docker image built for Linux/amd64 architecture. Docker images are standalone, executable packages that contain everything you need to run your application, including the code, runtime, libraries, dependencies, and configuration files. They are built from a Dockerfile, which contains instructions for assembling the image layer by layer.
Docker images are stored in repositories called registries, such as Docker Hub, where they can be versioned, tagged, and distributed. They can be easily shared and deployed across different environments, making Docker images a portable and scalable solution for packaging and distributing software applications.
With Sevalla, you can choose to use a public Docker image from any provider without authentication; however, it's important that you evaluate code quality and security and adhere to licensing and compliance requirements. You can also use a private image from any (or all) of the following registries:
* GitHub (ghcr.io)
* GitLab (registry.gitlab.com)
* Docker Hub (docker.io)
Sevalla only supports Docker images built for Linux/amd64 architecture. This is validated when you add an application and during the rollout phase.
Private images require authentication through your registry credentials. You can add your registry credentials within **Integration** > **Registry credentials** > **Create registry credential**.
Complete the fields as follows:
* **Name:** Enter a name for the registry credentials to identify them when adding your application.
* **Registry:** Choose from one of the following:
* DockerHub
* GitHub Container Registry
* GitLab Container Registry
* **Username:** Enter your username for the registry provider.
* **Personal access token:** You must obtain this from the registry provider. For more information about how to obtain a personal access token, refer to one of the following:
* [DockerHub](https://docs.docker.com/security/access-tokens/)
* [GitHub](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
* [GitLab](https://docs.gitlab.com/user/profile/personal_access_tokens/)
Click **Create registry credential**.
Once you've added the required registry credentials, you can select the credentials you want to use within **Applications** > ***app name*** > **Settings** > **Build strategy** > **Update build strategy**.
# Applications - Domains
Source: https://docs.sevalla.com/applications/domains
Add and manage custom domains for your applications.
When you host your application with Sevalla, it's automatically assigned a free sevalla.app domain as the primary domain upon successful deployment. This allows you to build, test, and preview your application before connecting your custom domain.
When you're ready to make your application live, you can add your custom domain on the **Domains** page. Every custom domain you add automatically includes a free SSL certificate. The temporary sevalla.app domains are automatically covered by the wildcard certificate of sevalla.app domain. (\*.sevalla.app). If you want to add a custom SSL certificate, please [contact our Support Team](https://docs.sevalla.com/support/contact-support), who can manually upload this for you.
Newly created applications use sevalla.app as the temporary domain. As Sevalla is a [Kinsta](https://kinsta.com) product, we previously used kinsta.app temporary domains for applications. This is a normal part of the Sevalla experience. Your application will still be accessible and manageable through Sevalla's interface even if it uses the kinsta.app domain.
If you use a **Hobby** pod for an application's web process, you will **not** be able to add a custom domain to your application. You can upgrade your pod within [Processes](/applications/processes/) at any time in order to add a custom domain.
## Add domain
In [Sevalla,](https://app.sevalla.com/) go to **Applications** > ***app name*** > **Domains**.
Click **Add custom domain** and enter your domain name. If you want to cover all subdomains, select **Wildcard** and then click **Add custom domain**.
If you add your domain without the wildcard subdomain, you should also consider adding the www version of the domain without the wildcard to ensure both versions are correctly configured.
## Verify domain
To verify your domain, you need to add the records shown to your domain's DNS records: an ownership TXT record, plus an SSL validation record whose type depends on your domain. Some DNS providers, such as [Namecheap](https://www.namecheap.com/), [Spaceship](https://www.spaceship.com/), and [Squarespace](https://www.squarespace.com/) need the short version of DNS record names. Sevalla automatically provides both the full and short versions of each record, so you can use whichever format your DNS provider needs.
**Ownership record (TXT)**
This TXT record allows Cloudflare to verify that you own the domain and are authorized to use their services for that domain. Once the domain is fully validated, you can remove this record from your DNS if necessary.
* Type: `TXT`
* Name: `_cf-custom-hostname`
* Value: Unique UUID value from Sevalla (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
**SSL validation record (`_acme-challenge`)**
Sevalla uses this DNS entry to issue and renew your SSL certificate. As long as this record exists in your DNS, you won't need to manually renew your SSL certificate; Sevalla manages it for you. We don't recommend removing this DNS entry, as you will need to re-add it each time the SSL certificate requires renewal.
The record **type depends on whether your domain is a wildcard**. Add it exactly as Sevalla shows it:
* **Standard (non-wildcard) domains** - add a **TXT** record:
* Type: `TXT`
* Name: `_acme-challenge`
* Value: the validation token shown in Sevalla
* **Wildcard domains** - add a **CNAME** record:
* Type: `CNAME`
* Name: `_acme-challenge`
* Value: `example.com.[unique verification token].dcv.cloudflare.com`
Allow 5-10 minutes for DNS to propagate. If propagation doesn't occur as expected, you can use a DNS lookup tool, such as [dnschecker.org](https://dnschecker.org/) or [mxtoolbox.com](https://mxtoolbox.com/), to verify if the record is resolving correctly.
## Point domain
Once your domain is successfully verified, you can point it by adding the required A records to your domain's DNS settings.
Some DNS providers, such as [Namecheap](https://www.namecheap.com/), [Spaceship](https://www.spaceship.com/), and [Squarespace](https://www.squarespace.com/), need the short version of DNS record names. Sevalla automatically provides both the full and short versions of each record, so you can use whichever format your DNS provider needs.
If you select the **Wildcard** option, an additional A record for `*.yourdomain.com` appears to add to your domain's DNS settings, which ensures all subdomains are covered.
When the domain is successfully pointed, a success message appears.
### Point WWW domain
We recommend that you point the www version of your domain to Sevalla (if you haven't already). To do so, add the www version of the domain to Sevalla and repeat the steps to verify and point the subdomain.
## Proxying through your own Cloudflare (Orange-to-Orange)
Sevalla's infrastructure already runs behind Cloudflare. If your DNS is also on Cloudflare and you enable the proxy (orange cloud) on the records that point to Sevalla, your traffic passes through two Cloudflare zones - your own and Sevalla's. This is known as an Orange-to-Orange (O2O) setup, and it comes with trade-offs:
* **SSL certificate renewal problems:** Sevalla issues and renews your SSL certificate through the `_acme-challenge` record. When your zone proxies the domain, renewal validation can fail, which can leave your domain with an expired certificate. Always keep the verification records (`_cf-custom-hostname` and `_acme-challenge`) set to **DNS only** (grey cloud).
* **Caching issues:** Your Cloudflare zone caches content in front of Sevalla's [CDN](/applications/cdn) and [edge caching](/applications/edge-caching). Purging the cache in Sevalla does not purge your own zone's cache, so visitors can be served stale content, and conflicting cache rules between the two layers can cause unexpected behavior.
For most setups, we recommend leaving the records that point to Sevalla set to **DNS only** (grey cloud) and using Sevalla's built-in CDN and edge caching instead. If you keep the proxy enabled, purge the cache in your own Cloudflare zone as well whenever you purge Sevalla's cache or troubleshoot stale content.
## Change your primary domain
In the domains list, locate the domain you want to be the primary domain, click the kebab (three-dot) menu, and click **Make primary domain**. Verify that the correct domain is selected, then click **Continue**.
## IP address
The IP address is shown when you point your domain. We use Cloudflare to secure our hosting infrastructure, so the corresponding IP you see for your application is a Cloudflare IP address. This means the owner of the IP address is Cloudflare, Inc., located in the United States of America.
The IP address doesn't reflect the physical place where your application is hosted, nor does it add any further latency to your application. Your application files are stored in the [data center location](/service-information/data-center-locations/) you choose. We do not create copies of your application and store those copies elsewhere.
We do not offer dedicated IP addresses because they aren't necessary for most configurations. Since our infrastructure is secured by Cloudflare, sites, applications, and databases hosted on Sevalla use a range of shared IP addresses provided by Cloudflare. Our Cloudflare IP addresses are reserved for Sevalla customers only, so you won't share an IP address with spam or adult sites or applications hosted elsewhere.
## Troubleshoot domain issues
Most domain problems happen during verification or pointing, and they usually come down to a conflicting or mis-entered DNS record. Work through the checks below in order.
### Domain won't verify
If your domain stays unverified after you've added the records Sevalla shows, check the following:
* **Remove any existing A or CNAME record on the root domain.** If your domain already has an A or CNAME record (for example, pointing to a previous host), Cloudflare tries to verify ownership through that record, and verification fails. Remove the old A or CNAME record before verifying, then add the records Sevalla provides.
* **Confirm the `_acme-challenge` record uses the correct type.** The required type depends on whether the domain is a wildcard. For a standard (non-wildcard) domain, add `_acme-challenge` as a **TXT** record. For a wildcard domain, add it as a **CNAME** record (its value ends in `dcv.cloudflare.com`). Always match the exact record type Sevalla shows - using the wrong type prevents the SSL certificate from being issued.
* **Disable the Cloudflare proxy on the verification records.** If you use Cloudflare as your DNS provider, set the verification records to **DNS only** (grey cloud). Proxied (orange cloud) records don't resolve publicly, so verification can't complete. You can re-enable the proxy on your A or CNAME records after the domain is active.
* **Remove conflicting or stale records.** If you previously added and removed this domain in Sevalla, an old `_cf-custom-hostname` TXT value may still be in your DNS. Delete any outdated `_cf-custom-hostname` or `_acme-challenge` records and re-add the exact values shown in Sevalla.
* **Confirm the value matches exactly.** Copy the value directly from Sevalla. A trailing space, a missing character, or a wrong record name causes verification to fail.
* **Check the Time-to-Live (TTL) setting.** This controls how long internet providers and other services remember your DNS settings before checking for updates. It is usually set to Auto or 5 minutes, but if it has been changed to a longer period, DNS propagation can take longer to take effect.
Allow 5-10 minutes after each change for DNS to propagate. Use [dnschecker.org](https://dnschecker.org/) or [mxtoolbox.com](https://mxtoolbox.com/) to confirm a record resolves before assuming it's wrong.
### SSL certificate isn't issued
Sevalla issues and renews your SSL certificate automatically once the domain is verified. If the certificate stays pending:
* Keep the `_acme-challenge` record in place (a TXT record for standard domains, or a CNAME record for wildcard domains). Removing it stops Sevalla from renewing your certificate, and you would need to re-add it.
* Check for a CAA record conflict, described in **Fix domain error** below.
### Fix domain error (CAA record conflict)
During the domain verification process, if a **Fix domain error** button appears next to the domain, this means a CAA record conflict is occurring.
A CAA record is an optional DNS record that lets you specify which certificate authorities (CAs) are allowed to issue SSL certificates for your domain. If a domain has no CAA records, any CA can generate an SSL certificate for it if requested. If a domain has a CAA record, only the CA(s) specified in the CA record can generate an SSL certificate for the domain.
To resolve this error, click the **Fix domain error** button and update the CAA record as indicated in the modal/pop-up. Alternatively, if you do not need a CAA record on your domain, you can remove the CAA record.
### Domain verified, but the application doesn't load
If the domain verifies but doesn't serve your application:
* Confirm the A record (or CNAME) matches the exact value shown on the **Point domain** step in Sevalla. If you reused an old record, update it.
* If you use the Cloudflare proxy, make sure it's enabled only on the A or CNAME records that point to Sevalla, not on the verification records.
* For wildcard domains, confirm you also added the `*.yourdomain.com` A record.
### Check your DNS records
You can see what's actually published for your domain with these commands:
```bash theme={null}
dig +short yourdomain.com A # Existing A record (remove before verifying)
dig +short yourdomain.com CNAME # Existing CNAME (remove before verifying)
dig +short _cf-custom-hostname.yourdomain.com TXT # Ownership TXT - must match the value in Sevalla
dig +short _acme-challenge.yourdomain.com TXT # SSL validation - standard (non-wildcard) domains
dig +short _acme-challenge.yourdomain.com CNAME # SSL validation - wildcard domains
```
If the published values don't match what Sevalla shows, update your DNS records and wait for propagation. If they match and the domain still won't verify, [contact our Support Team](https://docs.sevalla.com/support/contact-support).
# Edge caching
Source: https://docs.sevalla.com/applications/edge-caching
Optimize your content delivery using edge caching strategies.
Edge Caching saves your Sevalla site/page cache (which is only saved to your site's data center) to any of Cloudflare's global network of 260+ data centers. When your visitors load your application in their browser, cached responses will be delivered from the location closest to them, increasing the performance and speed of your application.
Edge Caching serves your Sevalla site/page cache but does not serve static assets like images, JavaScript files, and CSS files. Sevalla's [CDN](/applications/cdn/), which is independent of Edge Caching, can be enabled to serve your static assets. If Sevalla CDN is enabled, your site has an additional caching layer managed separately from Edge Caching. When you clear the Edge Cache for applications, this also clears the CDN cache.
Edge Caching is **not** enabled by default on Application Hosting. The application's **Overview** page shows if Edge Caching is enabled or disabled.
## Enable or disable edge caching
To enable edge caching within Sevalla, click **Applications** > **app name** > **Networking**, and within **CDN & Edge caching**, click **Update settings**.
To enable edge caching, select **Edge caching**.
## Clear edge cache
Sevalla automatically purges the edge cache after every successful deploy, so updated content is served without any manual action in most cases.
To clear the edge cache, within Sevalla, click **Applications** > **app name** > **Networking**, and within **CDN & Edge caching**, click **Purge cache**. If both CDN and edge caching are enabled, purging the cache will apply to both.
You can also clear the Edge Cache by sending a `POST` request with the [clear-cache API endpoint](https://api-docs.sevalla.com/v3/applications/purge-edge-cache). If you have enabled the [CDN](/applications/cdn/), this also clears the CDN cache.
Clearing Edge Cache in all of Cloudflare's data centers may take 2-5 minutes to fully complete.
# Applications - Environment variables
Source: https://docs.sevalla.com/applications/environment-variables
Set and manage environment variables for your app configurations.
Environment variables are useful for feeding your application information from outside the running of that application. They are typically used to set things like database connection details and API keys.
You can access your environment variables within **Applications** > ***app name*** > **Environment variables**.
**Copy all** copies all environment variables, allowing you to paste them elsewhere. **Export to file** exports all the environment variables; if you only want to export certain values, select the required environment variables and then click **Export to file**.
You cannot use a `.env` file to pass environment variables to the application; you must set them in Sevalla. You can import the contents of a `.env` file when you add environment variables.
## Special characters in environment variables
In the environment variable keys, you can only use a-z, 0-9, or underscore (`_`). Environment variable values are applied literally, with the exception of parentheses, commas, and double quotes.
### Parentheses
Parentheses can cause the build or rollout process to fail, depending on when they are available during deployment. They cannot be used in environment variables.
### Commas
Unescaped [commas are interpreted as delimiters](/applications/troubleshooting/failed-deployment#environment-variables) and cannot be used in environment variables.
* For example: `write_stock,read_orders` will cause the rollout process to fail.
* To keep a comma inside a string, escape it with a backslash (`\`) like this: `write_stock\,read_orders` — which will be applied as `write_stock,read_orders`.
### Double quotes
Unescaped double quotes are either disregarded or will cause the rollout process to fail.
* For example, `"my_example_variable"` will be applied as `my_example_variable`.
* To keep double quotes around a variable, escape them with a backslash (`\`) like this: `\"my_example_var\"` — which will be applied as `"my_example_var"`.
* If double quotes are inside of a string (e.g. `my_exampl"e_text`), the [rollout process will fail](/applications/troubleshooting/failed-deployment).
* To keep double quotes inside a string, escape them with a backslash (`\`) like this: `my_examp\"le_var` — which will be applied as `my_examp"le_var`.
### Base64 encoded variables
If your environment variable is Base64 encoded and you experience issues (e.g. 500 errors in the browser, build errors, runtime errors, etc.), try wrapping the value of the variable with single quotes.
## Add environment variables
If you use a Dockerfile to build your application and you want the environment variable to be available during build time, you must add ARG ENVVAR\_XY to your Dockerfile, where ENVVAR\_XY is the environment variable. For example, if your environment variable is DB\_CONNECTION\_URL you would need to add ARG DB\_CONNECTION\_URL.
To add environment variables, click **Add environment variables**. Add the key-value pairs in the **Add environment variable** modal/pop-up window, select if the variables are to be available during runtime and/or the build process, and click **Add environment variables**.
You can reference another environment variable using the `${key}` format. For example, to reference an environment variable with the key `DB_PASSWORD` use `${DB_PASSWORD}`.
To add multiple environment variables, copy the keys and values using CMD + C (Mac) or CTRL + C (Windows), and in the **Add environment variable** window, press CMD + V (Mac) or CTRL + V (Windows). You can also paste the contents of a `.env` file or import the `.env` file using **Import .env**.
To deploy the changes, click **Deployments** > **Deploy now**.
## Edit environment variables
You can edit variable names (keys) or values on the **Environment variables** page. To edit a variable, click the ellipsis (three dots) and click **Update**, make your changes, and click **Update environment variable**. To deploy the changes, click **Deployments** > **Deploy now**.
When you create an [internal connection](/applications/networking/) and select the **Add environment variables…** checkbox, the variable names (keys) are automatically created. Some applications may expect environment variables with different names. For example, if you want to use a database with Laravel, the **database.php** file contains variable names different from those automatically created in Sevalla. To use the variable names defined in the application, edit each variable as needed and change the key to match what's defined in the **database.php** file.
## Use environment variables
How you use environment variables depends on your application. In Node, for example, you can access a variable named `API_KEY` with `process.env.API_KEY`. In PHP, you would use `getenv('API_KEY')`.
## Environment variables set by Sevalla
The following environment variables are automatically injected into applications during both the **build** and **runtime** phases:
* `SVL_COMPANY_ID`
* `SVL_APP_ID`
* `SVL_APP_NAME`
* `SVL_PROCESS_ID`
* `SVL_PROCESS_TYPE`
* `SVL_DEPLOYMENT_ID`
* `SVL_DEPLOYMENT_INITIATED_BY`
* `SVL_DEPLOYMENT_TRIGGER`
* `SVL_DEPLOYMENT_COMMIT_SHA`
* `SVL_DEPLOYMENT_BRANCH`
* `SVL_DEPLOYMENT_DOCKER_IMAGE`
These variables make it easier to automate tasks, track deployments, and access key deployment metadata directly from within your application.
Sevalla always sets `PORT` as the [port used by the web server](/applications/networking#edit-application-port). If you'd like your application to interact with the web server, you will need to use this environment variable. For example, in Node.js, this is how you would start a server:
```javascript theme={null}
app.listen(process.env.PORT, () => {
console.log("Weather server is up and running")
})
```
## Environment variables not set by Sevalla
By default, the `NODE_ENV` environment variable is **not** set to `production` for Node.js applications, you must add this environment variable manually.
## Environment variable language examples
How you use environment variables depends on your application. The following table shows how to call an environment variable named API\_KEY in various languages:
| Language | Code |
| -------- | --------------------------- |
| Ruby | `ENV["API_KEY"]` |
| Node.js | `process.env.API_KEY;` |
| Python | `os.environ.get('API_KEY')` |
| Java | `System.getenv("API_KEY");` |
| Scala | `System.getenv("API_KEY");` |
| PHP | `getenv('API_KEY');` |
| Go | `os.Getenv("API_KEY")` |
# Add an application
Source: https://docs.sevalla.com/applications/get-started/add-an-application
Follow this guide to add a new application to the platform.
To help get you started and provide examples of minimal applications, you can use one of the Sevalla one-click templates from your **Dashboard** or from **Templates**. To access these templates, you must have a valid payment method on your account.
Click on one of the template options, and this automatically starts the application deployment.
To add an application, log in to [Sevalla](https://app.sevalla.com/) and click **Applications** > **Create** > **Application**. When you add an application, you can choose to link a [Git repository](/applications/git/overview) or Docker image; the add application workflow differs depending on which option you choose.
## Add an application using a private Git repository
* **Git provider:** Choose [GitHub](/applications/git/github), [Bitbucket](/applications/git/bitbucket), or [GitLab](/applications/git/gitlab) and connect your account.
* **Repository** and **Branch:** Choose a Git repository and a default branch. If the repository selector is blank, this may be because the account is new; for security, the creation date must be more than 30 days ago. If it is less than 30 days and you want to connect the Git account to Sevalla, ensure you have a valid [payment method](/billing/payments) on your Sevalla account and contact [Sevalla’s Support Team](/support/contact-support).
* **Auto-deploy:** Select this option to automatically deploy each time a commit is made to the selected branch.
* **Name:** This name will be displayed in Sevalla for easy reference.
* **Project:** This option is only shown if your company already has at least one project. Select the project you’d like to add the application to, or leave it blank to keep the application at the company level instead of assigning it to a specific project.
* **Location:** Choose the [data center](/service-information/data-center-locations/) you want to use for this application.
Currently, internal connections are only supported between applications and databases in the same region. If you'd like to use a database with your application, you can create the database at Sevalla and use an internal connection between the two (on the application's Settings page or the database's Info page).
* **Resource:** Choose the pod size for your process. This determines the CPU and RAM dedicated to the process.
If you choose a **Hobby** pod size for your web process, you will **not** be able to [add a custom domain to your application](/applications/domains/). However, if you need a custom domain for your application, you can upgrade it anytime.
**Overview** allows you to review your application's costs. Click **Create application**.
Once you've created your application, you can add [environment variables](/applications/environment-variables/), background workers, cron jobs, or jobs within the [Processes](/applications/processes/) page, and [persistent storage](/applications/storage). If your application is stateless (no persistent storage), you can also enable [automatic horizontal scaling](/applications/scalability) for the **web process** within **Processes**. This lets you set a minimum and maximum number of instances (up to 10) that the process can scale between as needed. Once you have everything set up for your application, you can deploy it from the **Overview** or **Deployments** page.
## Add an application using a public Git repository
* **Repository URL** and **Branch**: Enter the **Repository URL** and choose a **Branch**.
* **Name:** This name will be displayed in Sevalla for easy reference.
* **Project:** This option is only shown if your company already has at least one project. Select the project you’d like to add the application to, or leave it blank to keep the application at the company level instead of assigning it to a specific project.
* **Location:** Choose the [data center](/service-information/data-center-locations/) you want to use for this application.
Currently, internal connections are only supported between applications and databases in the same region. If you'd like to use a database with your application, you can create the database at Sevalla and use an internal connection between the two (on the application's Settings page or the database's Info page).
* **Resource:** Choose the pod size for your process. This determines the CPU and RAM dedicated to the process.
If you choose a **Hobby** pod size for your web process, you will **not** be able to [add a custom domain to your application](/applications/domains/). However, if you need a custom domain for your application, you can upgrade it anytime.
**Overview** allows you to review your application's costs. Click **Create application**.
Once you've created your application, you can add [environment variables](/applications/environment-variables/), background workers, cron jobs, or jobs within the [Processes](/applications/processes/) page, and [persistent storage](/applications/storage). If your application is stateless (no persistent storage), you can also enable [automatic horizontal scaling](/applications/scalability) for the **web process** within **Processes**. This lets you set a minimum and maximum number of instances (up to 10) that the process can scale between as needed. Once you have everything set up for your application, you can deploy it from the **Overview** or **Deployments** page.
## Add an application using a Docker image
Sevalla only supports Docker images built for Linux/amd64 architecture. This is validated when you add an application and during the rollout phase.
* **Docker image:** Enter the path to the Docker image. You can use public Docker images from any registry provider. You can access private Docker images from GitHub (ghcr.io), GitLab (registry.gitlab.com), or Docker Hub (docker.io) registries.
* **Registry credential (optional):** This is only required for private Docker images. You must enter your registry credentials within **Integration** > **Registry credentials**. Once you've entered your credentials in the Company settings, you can choose which credentials you want to use.
* **Name:** This name will be displayed in Sevalla for easy reference.
* **Project:** This option is only shown if your company already has at least one project. Select the project you’d like to add the application to, or leave it blank to keep the application at the company level instead of assigning it to a specific project.
* **Location:** Choose the [data center](/service-information/data-center-locations/) you want to use for this application.
Currently, internal connections are only supported between applications and databases in the same region. If you'd like to use a database with your application, you can create the database at Sevalla and use an internal connection between the two (on the application's Settings page or the database's Info page).
* **Resources:** Choose the pod size for your process. This determines the CPU and RAM dedicated to the process.
If you choose a **Hobby** pod size for your web process, you will **not** be able to [add a custom domain to your application](/applications/domains/). However, if you need a custom domain for your application, you can upgrade it anytime.
**Overview** allows you to review your application's costs. Click **Create application**.
Once you've created your application, you can add [environment variables](/applications/environment-variables/), background workers, cron jobs, or jobs within the [Processes](/applications/processes/) page, and [persistent storage](/applications/storage). If your application is stateless (no persistent storage), you can also enable [automatic horizontal scaling](/applications/scalability) for the **web process** within **Processes**. This lets you set a minimum and maximum number of instances (up to 10) that the process can scale between as needed. Once you have everything set up for your application, you can deploy it from the **Overview** or **Deployments** page.
## View app
Once your application is successfully deployed, you can open it using **View** at the top of the **Overview** page within the application in Sevalla. The **Overview** page also shows you a diagram of your application so you can easily visualize its components and which [ports](/applications/networking#edit-application-port) it is listening on for incoming requests.
# Checklist
Source: https://docs.sevalla.com/applications/get-started/checklist
Use this checklist to verify your application setup and deployment.
Follow the go-live checklist to ensure you have everything ready to get your application up and running quickly on Sevalla's Application Hosting. If you run into any problems or have questions, we're happy to help.
To help you get started with Application Hosting, you can use one of our [example templates](/templates/overview), a public Git repository, or a Docker image.
## 1. Git repository or Docker image
You must ensure the application you want to host exists within a Git repository or Docker image.
If you use a public Git repository, you need the URL and branch of the repository. If you want to use a private Git repository, you must select a Git service provider and repository from your account. You can choose from any (or all) of the following:
* [Bitbucket](/applications/git/bitbucket)
* [GitHub](/applications/git/github)
* [GitLab](/applications/git/gitlab)
If you use a public Docker image, you need the path to the Docker image. If you want to use a private Docker image, you must add your registry credentials within **Integration** > **Registry credentials**. You can choose from any (or all) of the following registries:
* GitHub (ghcr.io)
* GitLab (registry.gitlab.com)
* Docker Hub (docker.io)
## 2. Environment variables
Ensure you have all of the required [Environment variables](/applications/environment-variables/) for your application. Environment variables feed your application information from outside of the running of the application. They typically set things like database connection details and API keys.
## 3. Build path
An incorrect build path can cause the application deployment to fail. This is the path in the repository to the files required to build the application. Most applications are built from the repository root, and the **Build path** defaults to this (.). If you have a different build path, you must specify this within [**Settings**](/applications/settings/) (**Settings** > **Build strategy** > **Update build strategy** > **Build path**). For example, if your application needs to be built from a subdirectory (e.g. **app**), enter that subdirectory path in the **Build path** field: **app**.
## 4. Start command or ENTRYPOINT
The **Start command** for the [web process](/applications/processes/) starts your application. If this is incorrect, the application will not run. You can specify the Start command within **Processes** > **Web process** > **Update process**.
If your application uses a [Dockerfile](/applications/build-options/dockerfile) to set up your container image, you must specify the `ENTRYPOINT` in the Dockerfile to run a container. For more information about how to specify your application's `ENTRYPOINT`, see the [Dockerfile reference](https://docs.docker.com/reference/dockerfile/#entrypoint).
## 5. Background workers and cron jobs
Determine if your application requires additional processes like a [background worker](/applications/processes#background-worker) or [cron job](/applications/processes#cron-job-process); you can add these on your application's [Processes](/applications/processes) page.
## 6. Disk or persistent storage
If your application requires [persistent storage](/applications/storage), you can add this to your web process and background workers within **Disks**.
If you require persistent storage, you need to know the location of the files within your application to be added to the persistent storage disk, so you can specify this in the **Mount path**.
## 7. Add your domain to Sevalla
After you've confirmed your site is all good, it's time to go live with your custom domain. Check out our [Application - Domains guide](/applications/domains/).
# Applications - Features
Source: https://docs.sevalla.com/applications/get-started/features
Discover the platform features that make your app development easier.
Sevalla's Application Hosting supports a Git-based workflow and lets you deploy your site to one of [25 data centers](/service-information/data-center-locations/). You can deploy almost any application directly from source code right onto Sevalla infrastructure. You can choose the [resources](https://sevalla.com/application-hosting/pricing/) to best suit your application requirements, including options for a Hobby pod, standard pods, memory-optimized pods, and CPU-optimized pods. Each application pod has a predefined amount of CPU cycles, RAM, and build time.
Application Hosting includes the following features:
* **Unlimited users**: You can invite as many [users](/company-settings/user-management/) as required to your company or site with different levels of access, depending on what their role is.
* **Unlimited applications**: You can [add as many applications](/applications/get-started/add-an-application) as you want within your company, each with the resources required for the specific application, including multiple processes per application.
* **Unlimited concurrent builds**: You can build and deploy multiple applications simultaneously, and they don't impact one another.
* **Unlimited domains**: If you have a standard, memory-optimized, or CPU-optimized pod, you can add as many [domains](/applications/domains/) as required to each application.
* **Unlimited background workers, cron jobs, and jobs**: You can add as many [background workers, cron jobs, or job processes](/applications/processes/) as required for your application. Each process requires at least one pod to run, and you can specify the pod size and instances for each process.
* **Pipelines:** Use [pipelines](/applications/get-started/pipelines/) to seamlessly push changes from your source code to QA and production environments without needing to rebuild the application.
* **Persistent storage**: You can add a [storage volume](/applications/storage) to your web process or background workers that retains data even if the application is restarted or redeployed to create stateful applications. You can only have one storage volume per process with a disk size of up to 1 TB.
* **Automatic setup of environment and dependencies**: When you add your application from a Git repository, you can choose from [Nixpacks](/applications/build-options/nixpacks), [Railpack](/applications/build-options/railpack), or [Buildpacks](/applications/build-options/buildpacks) to automatically install dependencies for your application and configure your environment based on your repository. Nixpacks supports over 20 languages, Railpack supports 10, and Buildpacks supports 7; if you want to use a language that Nixpacks, Railpack, or Buildpacks do not support, you can also use a [Dockerfile](/applications/build-options/dockerfile) to set up your container image. This means you can use almost any language in your application and host it on Sevalla.
* **Zero downtime deployments and continuous monitoring with healthcheck:** If your application includes a [healthcheck](/applications/deployments#zero-downtime-with-healthchecks), when you deploy or redeploy, the application continues to run until the new pods are ready. The healthcheck also continuously monitors the application and restarts the pods if it fails to respond.
* **Analytics**: Sevalla's [Analytics](/databases/analytics) provides you with in-depth information about your application's usage.
* **Private network**: If you host both your database and application on Sevalla, you can set up an [internal connection](/applications/networking/) to create a private network so everything is on the same cluster and you don't get charged for ingress traffic.
# Applications - Infrastructure
Source: https://docs.sevalla.com/applications/get-started/infrastructure
Get details about the infrastructure powering your apps.
When you host your application or database with Sevalla, your projects run on Sevalla’s top-tier infrastructure. In this guide, we'll dive a little into the details of our Application Hosting and Database Hosting infrastructure.
## Git repository or Docker image
The application's code can be stored within a public or private Git repository or Docker Image.
For private Git repositories, you can choose from any (or all) of the following:
* [Bitbucket](/applications/git/bitbucket)
* [GitHub](/applications/git/github)
* [GitLab](/applications/git/gitlab)
Docker images must be built for Linux/amd64 architecture. For private Docker images you can choose from any (or all) of the following registries:
* GitHub (ghcr.io)
* GitLab (registry.gitlab.com)
* Docker Hub (docker.io)
## Sevalla add/deploy application
In Sevalla, when you [add an application](/applications/get-started/add-an-application), it connects to the Git repository or Docker image to retrieve the application.
## Sevalla bot
If you have an application using a Git repository with Automatic deployment on commit enabled within the [application's settings](/applications/settings/), the Sevalla bot detects if you commit a change or merge to your repository; it then pulls the application from your Git service provider and deploys the updated version of the application.
## Sevalla build system
Sevalla builds an image of the application from the code. It knows what applications or modules to install for the application from the information in the [Nixpacks](/applications/build-options/nixpacks), [Railpack](/applications/build-options/railpack), [buildpacks](/applications/build-options/buildpacks) or [Dockerfile](/applications/build-options/dockerfile). The output is an image that can be turned into a container.
## Artifact registry
This stores the container images that are ready to deploy. Each application has a single image that can be used whenever it needs to be deployed.
## Kubernetes cluster
The image from the artifact registry is pushed to the cluster. This is a virtual machine (VM) where multiple containers can run. The clusters are tuned to ensure the request from the artifact registry finds the right container, the containers are running, and they have the right resources. If there are any issues with a container, the application is redeployed to another container. We use cri-o v1.23.x on our infrastructure; however, this version is not static and may be upgraded as we upgrade different components in the stack.
Our Kubernetes infrastructure supports a multi-tenant setup, where each application runs in its own containerized environment. Network isolation and multi-layer virtualization ensure security and prevent unauthorized access between applications. This design provides you with a reliable and secure hosting platform, enabling you to focus on your core business while we handle the underlying infrastructure. We deploy at least one cluster per region, with the potential for additional clusters based on the number of applications in each region. This system ensures optimal resource allocation and scalability to meet the growing needs of our clients.
## Cloudflare
When a visitor accesses the website for an application, it first accesses Cloudflare, which knows which cluster hosts the website. It then sends the access request to the correct cluster.
Currently, for Application Hosting and Database Hosting, Cloudflare includes the default firewall rules, the default DDoS protection, and other defaults.
## Cloud load balancing
Each cluster has a load balancer that receives the access request from Cloudflare and randomly pushes a VM worker node.
## Ingress
The VM worker node receives the request on the Ingress system, which knows which container is responsible for the hostname being requested. The Ingress system sends the request to the correct container, and if the container has a database attached, it communicates with the database and sends a response on the same route.
## Virtual Machines (VM)
A virtual machine (VM) can hold multiple containers and multiple databases.
## Containers
Each container or application can have multiple copies on the VM. In this case, the Ingress system knows this and randomly sends through one of the copies of the same container.
## Persistent storage
You can add [persistent storage](/applications/storage) to a web process or background processes. This adds a storage volume that is attached to the VM (virtual machine) for your application and retains data even if the application is restarted or redeployed.
# Pipelines
Source: https://docs.sevalla.com/applications/get-started/pipelines
Set up deployment pipelines for continuous delivery and integration.
Pipelines enable you to automate the entire process of moving code from development to production. You can define multiple stages within your pipeline and include multiple applications in each stage. Once your pipeline is set up, the **Promote** feature allows you to seamlessly push changes from the source code to QA and production environments without the need to rebuild the application. Pipelines also support the Git Flow strategy, providing a clear visual representation of your application's development and deployment workflow.
With pipelines, you can:
* **Deploy software with different environment variables:** This is ideal for scenarios like a B2B application used by multiple customers, where each customer requires slight variations in their dashboard.
* **Deploy the same application across multiple geographical locations:** This helps improve performance and reduce latency for users in different regions.
* **Run A/B tests:** Easily deploy different versions of your application to targeted user groups so you can test which version delivers better results.
Using pipelines streamlines the deployment process, enhances flexibility, and supports a structured approach to managing multiple environments.
With Pipelines, applications are **free** until they are deployed. Billing only begins once a deployment takes place and the application is actively running.
The **Promote** feature is also [accessible through our API](https://api-docs.sevalla.com/v3/pipelines/promote-pipeline), making it easy to integrate with third-party CI/CD tools like GitHub Actions for streamlined workflows.
Watch our video to see how to create a delivery pipeline for a Laravel application hosted on Sevalla.
## Add a pipeline
To add a new pipeline, within **Applications**, click **Create** > **Pipeline**.
* **Name:** Enter a name for the pipeline.
* **Project:** This option is only shown if your company already has at least one project. Select the project you’d like to add the pipeline to, or leave it blank to keep the pipeline at the company level instead of assigning it to a specific project.
* **Trunk-based development:** With a trunk-based development pipeline, you can add an existing application to your development stage and create multiple production environments as separate applications for deployment. Each of these applications can be hosted in different [data centers](/service-information/data-center-locations/) and is treated as an independent entity within its own container. This setup allows you to deploy multiple applications from the same source code but with distinct [environment variables](/applications/environment-variables/), [domains](/applications/domains/), [processes](/applications/processes), and other configurations.
* **Git flow:** Choose this option if your workflow uses separate branches for development, staging, and production. To use the Git Flow pipeline, your applications must already be set up within Sevalla. This approach lets you visually manage and track your Git Flow directly in the platform. The Promote feature is not available in this workflow, as deployments occur automatically when you push changes from your Git source repository.
You also have the flexibility to add multiple stages to the pipeline, such as a QA stage, to thoroughly test your changes before promoting them to production.
Click **Add pipeline**, which creates the pipeline in your list of applications. You can then select the pipeline to add your stages and applications, enable preview apps, and change the pipeline settings.
### Enable preview apps
Enabling preview apps allows you to test your changes in a live environment before merging them into the main branch. Preview apps are integrated with GitHub's deployment and environment features, so when you open a pull request, a preview app is automatically generated, providing a dedicated testing space that mirrors your production setup. This lets you review, interact with, and refine your updates to ensure your code works as intended before it's fully integrated into the main project.
To enable preview apps within the pipeline, click **Enable preview apps**.
When you click **Enable preview apps**, the following options are available:
#### Preview settings
* **Automatically create new preview apps for each pull request:** Select this option to create a new preview app each time you open a pull request. The preview app is deleted when the pull request is closed.
* **Delete stale preview apps automatically:** Select this option to automatically delete preview apps when no new deployments occur. You'll need to specify the number of days without any new deployments before the preview apps are scheduled for deletion.
#### App settings
* **Git provider:** Choose [GitHub](/applications/git/github), [GitLab](/applications/git/gitlab), or [Bitbucket](/applications/git/bitbucket) and connect your Git account.
* **Repository:** Choose a Git repository.
* **Location:** Choose the [data center](/service-information/data-center-locations/) you want to use for this application.
* **Build type:** Choose [Nixpacks](/applications/build-options/nixpacks), [Railpack](/applications/build-options/railpack), [Buildpacks](/applications/build-options/buildpacks), or a [Dockerfile](/applications/build-options/dockerfile).
* **Build path:** For Nixpacks, Railpack, and Buildpacks, this is the path in the repository to the files required to build the application. For Dockerfiles, this is the path to your Dockerfile relative to the repository root.
* [**Hibernation:**](/applications/settings#hibernation) This automatically scales down your application if no HTTP requests are received within the specified timeframe.
#### Processes
In this section, you can adjust the settings and resources for your web process and add any necessary [background workers](/applications/processes#background-worker), [jobs](/applications/processes#job-process), or [cron jobs](/applications/processes#cron-job-process).
#### Disks
If you require [persistent storage](/applications/storage) for your web process or any of your background workers, you can add it here.
#### TCP proxies
This option [exposes non-HTTP traffic](/applications/networking#tcp-proxy) for up to three processes over TCP using a proxied domain and port.
#### Environment variables
Add any required [environment variables](/applications/environment-variables/) for your preview app.
Once you've added the required details, click **Enable preview apps**.
To change the settings of the preview app, click **Preview app settings**.
To manually deploy the preview app, click the ellipsis on **Preview** and select **Deploy preview app**.
### Add an app to a stage
To add an application to a stage, click **Add app**. You can then choose to add an existing application or create a new one. You can only create a new application within the trunk-based development pipeline. If you're using the Git Flow pipeline, the applications must already exist within Sevalla.
For trunk-based pipelines, the first stage of your pipeline should be the source for the rest of the pipeline, so you must choose an existing application. You can then choose to create a new application for any of the following stages.
### Add a stage
To add another stage to the pipeline, click **Create stage**.
Enter a name for the stage and click **Create stage**. You can drag and drop the stages to change the order in which you want to deploy the application.
You can then add a new application to the stage.
### Promote changes to production
If you've set up a trunk-based pipeline, you can use the **Promote** option to push the application to each stage without having to rebuild it. If you're promoting to a stage with multiple applications, you can choose which applications to promote to. If you don't want to promote a particular application, click the minus sign on that application to remove it from the deployment.
Within **Applications**, the pipeline displays all the included applications, clearly labeling each application's stage within the pipeline and when it was last deployed.
## Pipeline settings
To access the pipeline settings, click **Pipeline settings**. The settings allow you to switch between trunk-based development and git flow pipelines. You can also update the name of your pipeline and change the order of the stages within it.
## Delete a pipeline
To delete a pipeline, within **Applications**, select the pipeline you want to delete and click **Delete pipeline**.
This only deletes the pipeline; the applications **are not** removed and will remain in your **Applications** list. To completely remove an application, go to **Settings** > **Danger Zone** > **Delete application**. Deleting the application completely removes the following:
* All files
* Settings
* Persistent storage disks
* Connections to other applications or databases
# Bitbucket
Source: https://docs.sevalla.com/applications/git/bitbucket
Connect Bitbucket repositories for streamlined deployments.
When adding an application, if you're using a private Git repository, you must select a Git provider and repository from your account. In addition to Bitbucket, you can also choose from [GitHub](/applications/git/github) or [GitLab](/applications/git/gitlab).
If you’re using Bitbucket and want to use GitHub repositories, you’ll need to import the repository from GitHub. Later in this guide, we’ll show you how to [import a GitHub repository into Bitbucket](#importing-a-github-repository).
For security, your Git account creation date must be more than 30 days old. If it is less than 30 days old and you want to connect the Git account to Sevalla, please contact Sevalla’s Support Team.
## Grant access to the Sevalla Bitbucket application
The first time you [add an application](/applications/get-started/add-an-application) in Sevalla, you’ll need to connect to a git provider so that Sevalla can access your application’s repository. When you click **Create** > **Application**, you must choose your git provider and connect Sevalla to your account.
You can only connect one Bitbucket account to each Sevalla user. If you want to connect a different Bitbucket account, you must remove Sevalla's access to Bitbucket and reconnect to the other Bitbucket account.
If you aren’t logged in to Bitbucket, you’ll need to log in. On the next page, you’ll need to confirm Kinsta’s access to your Bitbucket account.
There may be occasions when you need to re-authenticate your Bitbucket account, such as when we release an update to the Bitbucket integration or if the token has expired. You can view the expiration date for the token in your User settings (click on your username and go to User settings > Access).
You may notice that the confirmation process is facilitated by [Kinsta](https://kinsta.com). Don't worry, as Sevalla is a Kinsta product, this is a normal part of the Sevalla experience. You'll still be interacting with Sevalla's features and services. Just follow the prompts to complete the confirmation, and you'll be all set!
You will be returned to Sevalla. In **Application details**, select your application’s **Bitbucket repository** and **Default branch**. Then, continue with the rest of the Add application steps.
## Remove Sevalla's access to Bitbucket
To remove Sevalla’s access to your Bitbucket account, you’ll need to revoke access in your **User settings** in Sevalla and in Bitbucket:
In Sevalla, click on your username and go to **Account** > **Git login & repository access.** On **Repository access enabled**, click **Revoke** for the Bitbucket application and then click **Continue**.
This opens the Bitbucket App authorizations page, click **Revoke** next to the MyKinsta application.
## Importing a GitHub repository
1. Find the repository you want to use from [Sevalla’s example repositories at GitHub](https://github.com/orgs/kinsta/repositories?q=\&type=template\&language=\&sort=) and copy the URL.
2. In Bitbucket, click **Create** > **Repository** > **Import repository**.
3. Paste the URL of the Sevalla repository in the URL field, select the **Project** you want to add it to, and click **Import repository**.
4. When the import is complete, you can start using the repository in Bitbucket.
## Troubleshooting
### Missing repositories
If you’re having trouble seeing your repositories in **Add application**, you may need to re-authorize Sevalla’s access to Bitbucket. To do that, start by [removing access between Sevalla and Bitbucket](#remove-sevalla-access-to-bitbucket) as described above.
In **Add application**, go through the authentication and grant access steps to connect Sevalla to your Bitbucket account again.
### Conflicting namespaces
The `Conflicting namespaces` error appears when a Git account is connected to another Sevalla user account. Your Git account can only be linked to one Sevalla account; if you have multiple Sevalla accounts, you must use multiple Git accounts.
To resolve this error, you must log in to your other Sevalla account and [remove Sevalla access to Bitbucket](#remove-sevalla-access-to-bitbucket).
# GitHub
Source: https://docs.sevalla.com/applications/git/github
Deploy apps directly from your GitHub repositories.
When adding an application, if you're using a private Git repository, you must select a Git provider and repository from your account. In addition to GitHub, you can also choose from [Bitbucket](/applications/git/bitbucket) or [GitLab](/applications/git/gitlab).
With GitHub, you can also integrate the [Sevalla GitHub Action](https://github.com/marketplace/actions/sevalla-deploy) into your workflow to seamlessly promote and deploy your applications and static sites.
If you have a repository at another Git provider, you can [import that repository into GitHub](#import-a-repository-to-github) so you can connect it to your application hosted at Sevalla.
For security, your Git account creation date must be more than 30 days. If it is less than 30 days and you want to connect the Git account to Sevalla, please contact Sevalla’s Support Team.
## Authenticate and authorize
The first time you [add an application](/applications/get-started/add-an-application) in Sevalla, you’ll need to connect to a Git provider so that Sevalla can access your application’s repository. When you click **Create** > **Application**, you must choose your git provider and connect Sevalla to your account.
You can only connect one GitHub account to each Sevalla user. If you want to connect a different GitHub account, you must remove Sevalla's access to GitHub and reconnect to the other GitHub account.
If you aren’t currently logged in to GitHub, you’ll need to log in. On the next page, you’ll need to authenticate so you can authorize access. The last step is to authorize the Kinsta GitHub application for access to your GitHub account.
There may be occasions where you need to re-authenticate your GitHub account, for example, when we release an update to the GitHub integration or if the token has expired. You can view the expiration date for the token in your User settings (click on your username and go to User settings > Access). When the token expires, you can continue to deploy existing applications, but if you add a new one, you’ll need to connect your GitHub account again to generate a new access token.
Go back to Sevalla, where you can begin adding your application and installing the Kinsta GitHub application to your repository.
## Edit GitHub permissions
In **Add application**, click **Adjust GitHub repository access**.
This initiates the installation of the Kinsta GitHub application to your GitHub Account. If you have access to multiple accounts, choose the correct account to install it on.
If you do not have the correct access level, you may need to request authorization from an account owner or application manager to access the GitHub repo. For more information, see GitHub Roles in an Organization.
You may notice that the authorization process is facilitated by [Kinsta](https://kinsta.com). Don't worry, as Sevalla is a Kinsta product, this is a normal part of the Sevalla experience. You'll still be interacting with Sevalla's features and services. Just follow the prompts to complete the authorization, and you'll be all set!
On the next screen, you can specify exactly what this application has access to. We aim to have as little access as possible to your data, so we recommend not giving the application access to all repositories. Click **Only select repositories** and choose the repository you would like to deploy.
Click **Update access**, and you’re good to go. When you go back to Sevalla and click the **GitHub repository** field, you should see the authorized repository now available.
## Sevalla GitHub Action
You can seamlessly integrate Sevalla deployments into your [GitHub workflows](https://docs.github.com/en/actions/how-tos/write-workflows) using the official [Sevalla GitHub Action](https://github.com/marketplace/actions/sevalla-deploy).
With this integration, you can:
* Trigger a deployment for any Sevalla app using an API token or deploy hook.
* Promote deployments between Sevalla environments (e.g., staging to production).
* Deploy static sites directly from your workflow.
* Optionally, wait for the deployment to complete before continuing the workflow.
* Access the deployment or promotion ID as an output variable for use in subsequent steps.
This makes it easy to automate your CI/CD pipeline and streamline your release process directly from GitHub.
## Remove Sevalla's access to GitHub
You can remove Sevalla’s access to your GitHub account either through Sevalla or GitHub.
### Remove access via Sevalla
In Sevalla, click on your username and go to **Account.** In **Git login & repository access**, on **Repository access enabled**, click **Revoke** for the GitHub application.
### Remove access via GitHub
In GitHub, click on your user avatar and go to **Settings** > **Applications** > **Authorized GitHub Apps**. Click **Revoke** for the Kinsta GitHub application.
In the confirmation modal/pop-up, click **I understand, revoke access**.
If you try to add a new application in Sevalla, you must authenticate and authorize the Kinsta GitHub application to reconnect it to your GitHub account.
## Import a repository to GitHub
This guide assumes you already have a GitHub account. If not, visit their signup page to get started.
1. In GitHub, click the plus sign (**+**) in the upper-right corner and select **Import a repository**.
2. Copy the repository URL from your other Git provider and paste it into **Your old repository’s clone URL** in GitHub.
3. Enter your username and password or access token for the repository you are importing.
4. If you are a member of an [Organization](https://docs.github.com/en/organizations) in GitHub, choose an **Owner** for your new repository.
5. Enter your **Repository name**.
6. Choose a privacy setting for the new repository and click **Begin import**.
## Troubleshooting
### Missing repositories
If you’re having trouble seeing your repositories in **Add application**, you may need to re-authenticate and authorize the Kinsta GitHub application. To do that, start by [removing access between Sevalla and GitHub](#remove-sevalla-access-to-github) as described above.
In **Add application**, go through the authenticate and authorize steps to connect Sevalla to your GitHub account again.
### Conflicting namespaces
The `Conflicting namespaces` error appears when a Git account is connected to another Sevalla user account. Your Git account can only be linked to one Sevalla account; if you have multiple Sevalla accounts, you must use multiple Git accounts.
To resolve this error, you must log in to your other Sevalla account and [remove Sevalla access to GitHub](#remove-sevalla-access-to-github).
# Gitlab
Source: https://docs.sevalla.com/applications/git/gitlab
Integrate with Gitlab for automated application deployments.
When adding an application, if you're using a private Git repository, you must select a Git provider and repository from your account. In addition to GitLab, you can also choose from [Bitbucket](/applications/git/bitbucket) or [GitHub](/applications/git/github).
If you’re using GitLab and want to use GitHub repositories, you’ll need to [import the repository from GitHub](#import-a-github-repository).
For security, your Git account creation date must be more than 30 days. If it is less than 30 days and you want to connect the Git account to Sevalla, please contact Sevalla’s Support Team.
## Authorize the Sevalla GitLab application
The first time you [add an application](/applications/get-started/add-an-application) in Sevalla, you’ll need to connect to a Git provider so that Sevalla can access your application’s repository. When you click **Create** > **Application**, you must choose your git provider and connect Sevalla to your account.
You can only connect one GitLab account to each Sevalla user. If you want to connect a different GitLab account, you must remove Sevalla access to GitLab and reconnect to the other GitLab account.
If you aren’t logged in to GitLab, you’ll need to log in. On the next page, you’ll need to authorize the Kinsta GitLab application for access to your GitLab account.
There may be occasions when you need to re-authenticate your GitLab account, such as when we release an update to the GitLab integration or if the token has expired. You can view the expiration date for the token in your User settings (click on your username and go to User settings > Access).
You may notice that the authorization process is facilitated by [Kinsta](https://kinsta.com). Don't worry, as Sevalla is a Kinsta product, this is a normal part of the Sevalla experience. You'll still be interacting with Sevalla's features and services. Just follow the prompts to complete the authorization, and you'll be all set!
You will be returned to Sevalla. In **Application details**, select your application’s **GitLab repository** and **Default branch**. Then, continue with the rest of the Add application steps.
## Remove Sevalla's access to GitLab
In Sevalla, click on your username and go to **Account.** In **Git login & repository access**, on **Repository access enabled**, click **Revoke** for the GitLab application.
## Import a GitHub repository
1. Find the repository you want to use from [Sevalla’s example repositories at GitHub](https://github.com/orgs/kinsta/repositories?q=\&type=template\&language=\&sort=) and copy the URL.
2. In GitLab, click the plus icon in the top menu and go to **New project/repository** > **Import project** > **Repository by URL**.
3. Paste the URL of the Sevalla repository in the **Git repository URL** field, enter a **Project name**, and click **Create project**.
4. When the import is complete, you can start using the repository in GitLab.
## Troubleshooting
### Missing repositories
If you’re having trouble seeing your repositories in **Add application**, you may need to reauthorize Sevalla’s access to GitLab. To do that, start by [removing access between Sevalla and GitLab](#remove-sevalla-access-to-gitlab) as described above.
In **Add application**, go through the steps to connect Sevalla to your GitLab account again.
### Conflicting namespaces
The `Conflicting namespaces` error appears when a Git account is connected to another Sevalla user account. Your Git account can only be linked to one Sevalla account; if you have multiple Sevalla accounts, you must use multiple Git accounts.
To resolve this error, you must log in to your other Sevalla account and [remove Sevalla access to GitLab](#remove-sevalla-access-to-gitlab).
# Git overview
Source: https://docs.sevalla.com/applications/git/overview
Learn about the supported Git platforms and integration options.
When you add an application, you can choose to use a [Docker image](/applications/docker-images) or a Git repository. A Git repository is a directory or storage space where a Git project’s files and version history are stored. It contains all the files and directories associated with a project, along with metadata and version control information managed by Git.
In a Git repository, developers can track file changes over time, create and manage branches, collaborate with others, and synchronize changes.
With Sevalla, you can choose to use a public Git repository without authentication; however, it’s important that you evaluate code quality and security and adhere to licensing and compliance requirements. You can also use a private Git repository from any (or all) of the following service providers:
* [GitHub](/applications/git/github)
* [Bitbucket](/applications/git/bitbucket)
* [GitLab](/applications/git/gitlab)
When you connect to a private Git repository, you must authorize/grant access to Sevalla to verify your identity and access your Git repositories.
With GitHub, you can also integrate the [Sevalla GitHub Action](https://github.com/marketplace/actions/sevalla-deploy) into your workflow to seamlessly promote and deploy your applications and static sites.
As Sevalla is a [Kinsta](https://kinsta.com) product, you may notice that the integration process is facilitated by Kinsta. Don't worry - this is a normal part of the Sevalla experience, and you'll still be interacting with Sevalla's features and services. Just follow the prompts to complete the integration, and you'll be all set!
For security, your Git account creation date must be more than 30 days old. If it is less than 30 days old and you want to connect the Git account to Sevalla, please contact Sevalla’s Support Team.
You can also use your Git service provider login with [Single-Sign-On (SSO)](/user-settings/logging-in/#single-sign-on-sso) to sign up or log in to Sevalla.
# Go-live checklist
Source: https://docs.sevalla.com/applications/go-live-checklist
Run through this checklist before sending production traffic to a new application.
Before you send production traffic to a new application, run through this checklist. It walks through the Sevalla features that most directly affect uptime, resilience, and recoverability - health checks, deployment automation, scaling, networking, and backups - so your first day in production goes smoothly.
Use it as a final pass after your application is already deploying successfully, and before you point real users at it.
## 1. Configure health checks
Health checks are the single most important reliability feature to enable before go-live. Without them, Sevalla has no way to know if your application is actually able to serve traffic, or if it has silently hung.
Two probes are available per process:
* **Readiness probe** - determines whether the process should receive traffic. If it fails, the process is temporarily taken out of rotation until it passes again.
* **Liveness probe** - determines whether the process is still functioning. If it fails, the process is automatically restarted.
For each probe you can configure a custom **path** and **port**, which is useful if your app exposes a dedicated `/healthz`-style endpoint on a separate port from your main web traffic.
**Checklist:**
* [ ] Web process has a readiness probe pointing at a real endpoint (not just `/`)
* [ ] Liveness probe is configured if your app can end up in a hung/deadlocked state
* [ ] Health check endpoint doesn't depend on downstream services that could cause cascading restarts (e.g., don't fail your liveness check just because a third-party API is slow)
Beyond the configurable probes, Sevalla also runs its own background healthcheck monitoring during runtime: your app's healthcheck path is checked every 10 seconds, and if it fails to respond three times in a row, the pod is restarted automatically. This runs independently of deploy events, so a healthy healthcheck endpoint protects you during normal operation, not just during rollouts.
## 2. Use pipelines to control how code reaches production
If you're deploying straight from a branch to production, you're skipping one of the platform's main safety mechanisms. [Pipelines](/applications/get-started/pipelines) let you formalize the path code takes from commit to production and add gates along the way.
Two pipeline models are available:
* **Trunk-based development** - a development-stage application can be promoted into one or more separate production applications. Promotion can be triggered manually or via the API, making it straightforward to wire into external CI/CD tools like GitHub Actions.
* **Git Flow** - models separate branches for development, staging, and production directly in the platform, with deployments firing automatically on push to each branch.
Either model supports adding intermediate stages (e.g. a QA stage) and enabling **preview apps**, which spin up a live environment for a pull request so changes can be tested in isolation before merging.
**Checklist:**
* [ ] Production deploys go through at least one intermediate stage (QA/staging), not directly from a feature branch
* [ ] Promotion between stages is deliberate (manual click, PR merge, or API call) rather than automatic-everywhere
* [ ] Preview apps are enabled if your team reviews changes before merging
* [ ] Automatic deployments are explicitly enabled/disabled per stage as intended - check this in each application's Settings, since it's easy to leave a stage on auto-deploy by accident
* [ ] Database migrations run as a separate [job process](/applications/processes#job-process) with the right start policy (e.g. **before deployment**), not appended to the web process's start command
Running migrations as a dedicated job process, rather than as part of your web process's start command, means a failed migration blocks the deployment instead of crash-looping your web process, and gives you explicit control over whether migrations run before or after the new version goes live.
## 3. Set up autoscaling and right-size your resources
Every process has a **Resource** setting (CPU/RAM) and an optional **horizontal auto-scaling** setting. If auto-scaling is enabled, you define a minimum and maximum instance count for the web process. When CPU or memory usage on the current pod(s) crosses its target (80% by default, adjustable), an additional instance is added, up to your configured maximum. When usage drops, instances are scaled back down - never below your configured minimum.
Before go-live, decide deliberately rather than leaving this on defaults:
**Checklist:**
* [ ] Pod size (CPU/RAM) is based on real load testing, not a guess
* [ ] Horizontal auto-scaling is enabled for stateless web processes that expect variable traffic
* [ ] Minimum instance count is at least 2 for anything customer-facing, so a single pod restart doesn't cause a full outage
* [ ] Maximum instance count is set high enough to absorb a traffic spike, but with an eye on cost
* [ ] CPU/memory scaling targets are reviewed rather than left at the 80% default if your app has unusual usage patterns (e.g. memory-heavy but CPU-light)
* [ ] [Application Analytics](/applications/analytics) (**Applications > your app > Analytics**) has been checked under real load to confirm the pod size and scaling settings actually hold up - it breaks down CPU, memory, HTTP requests, and instance count per process
See [Scalability](/applications/scalability) for more on configuring vertical and horizontal scaling.
## 4. Lock down domains, SSL, and environment configuration
* **Custom domains**: every verified [custom domain](/applications/domains) is automatically covered by a free SSL certificate through Sevalla's Cloudflare integration (TLS 1.2/1.3). Only add a custom SSL certificate if you have a specific compliance or certificate-authority requirement - it isn't needed for standard HTTPS.
* **CDN**: if your application relies on `Cache-Control` headers to make static assets cacheable, turn on the [CDN](/applications/cdn) (**Applications > your app > Networking > CDN & Edge caching**) so Cloudflare's edge network actually honors them. The CDN is **not** enabled by default.
* **Environment variables and secrets**: confirm these are set in the application's [Environment Variables](/applications/environment-variables) tab rather than committed to the repo. If you use a framework where some variables are inlined at build time (for example, any client-exposed/public variables), make sure those are set *before* the build runs, not only as runtime values - a value added after the last build won't retroactively appear in an already-built bundle.
* **Ephemeral filesystem**: the container filesystem does not persist across redeploys or pod restarts. Anything your app writes to local disk at runtime (uploads, generated files, on-disk caches, SQLite files) will be lost. If you need it to persist, prefer moving it to [object storage](/object-storage/overview) over attaching a [persistent storage](/applications/storage) disk before go-live - not after you lose data.
**Checklist:**
* [ ] Production domain is added and shows a verified SSL status
* [ ] CDN is enabled if your app serves cacheable static assets with `Cache-Control` headers
* [ ] All required environment variables/secrets are set in Sevalla, not `.env` files in the repo
* [ ] Any local disk writes your app performs are backed by object storage, persistent storage, or other external storage
* [ ] DNS/verification records that Sevalla needs (e.g. `_acme-challenge`) are set to DNS-only rather than proxied, so certificate renewal doesn't silently fail later
Anything your app writes to local disk at runtime is lost on every redeploy or pod restart. Attach persistent storage or move writes to object/external storage before go-live, not after you lose data. Prefer object storage over a persistent storage disk wherever possible: persistent storage pins a process to a single instance and blocks horizontal scaling entirely (no auto-scaling, no multi-instance scaling), while object storage keeps your web and background processes stateless and free to scale horizontally.
## 5. Confirm database resilience
If your application uses a Sevalla-hosted database:
* Databases are backed up **automatically once a day**, with each automatic backup retained for **7 days**.
* You can also take up to **5 manual backups**, retained for **14 days** - useful immediately before a risky migration or schema change.
* Backups can be restored either into the same database or into a different one (the target must be in the same data center), which makes it possible to test a restore without touching production.
* If your application and database are both hosted on Sevalla, set up an internal/private connection between them. Traffic stays inside Sevalla's network, which is faster, doesn't incur internal bandwidth cost, and avoids exposing the database on the public internet.
**Checklist:**
* [ ] Application connects to the database over the internal/private connection, not a public endpoint
* [ ] You've taken at least one manual backup and confirmed you know how to restore it, before you need to do it under pressure
* [ ] Anyone who might need to restore a backup knows where the Backups page is and what "restore to a different database" does (it does not touch your live database)
## 6. Turn on failure notifications
Set up email notifications for failed deployments under your username > **User settings > Notifications**. Combined with the runtime healthcheck monitoring described in step 1, this closes the loop: healthchecks catch runtime problems automatically, and deployment notifications catch problems introduced by a bad release before you find out from a user.
**Checklist:**
* [ ] Failed-deployment email notifications are turned on for at least one team member who can act on them
* [ ] It's clear who is responsible for responding when a notification fires
## Go-live summary
| Area | Minimum bar before go-live |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Health checks | Readiness + liveness probes configured on a real endpoint |
| Pipeline | Production deploys pass through a QA/staging stage before promotion |
| Migrations | Run as a job process with the right start policy, not in the web process start command |
| Scaling | Horizontal auto-scaling on, minimum ≥ 2 instances for customer-facing apps |
| Resources | Pod size validated under real load via Application Analytics |
| Domains/SSL | Custom domain verified, SSL active |
| CDN | Enabled if your app depends on `Cache-Control` headers for static assets |
| Secrets | All config in Environment Variables, none committed to Git |
| Storage | No runtime writes to local disk without object/persistent/external storage; object storage preferred for horizontal scalability |
| Database | Internal connection in use, manual backup taken and restore tested |
| Alerts | Failed-deployment notifications enabled |
This list isn't exhaustive for every application type (queues, cron jobs, and multi-service pipelines each add their own considerations), but covers the checks that most commonly turn a rough launch into a smooth one.
# Applications - Networking
Source: https://docs.sevalla.com/applications/networking
Configure networking options for your applications, including internal and external access.
Networking is how applications can communicate with other applications or databases. There are two main ways this can be achieved:
* **Public networking:** Connections that are accessible from the Internet or external networks. This makes an Internet round-trip, so it can be slower than private networking. With Sevalla’s Application Hosting, you can connect to your application publicly using a specific port or TCP proxy.
* **Private networking:** Connections that stay within our network and are not directly accessible from the Internet. We strongly recommend this method if you’re connecting applications hosted on Sevalla or linking an application with a database also hosted on Sevalla. To use Sevalla’s private network, all applications and databases must use the same data center.
Internal connections are only available between applications and databases hosted with Application Hosting and Database Hosting services.
You can configure your application's public or private port, disable HTTP(S) traffic, or add an internal connection within **Applications** > ***app name*** > **Networking**.
## Public networking
### Expose HTTP traffic
Configure a specific port for your application for HTTP traffic, change the protocol, or disable HTTP traffic.
#### Update protocol
Use this to switch the web process protocol between **HTTP** and **gRPC**. [gRPC](https://grpc.io/) is a protocol that allows browser-based applications to connect with gRPC services over HTTP so different parts of an application, or even different applications, can communicate with each other efficiently over a network.
#### Update port
By default, the port for your application’s web process is 8080. When an application is deployed, it is reachable on the internet on ports 80 and 443, and we route those ports to the container on the port defined by your application. This port is available during application runtime on the \$PORT environment variable. You can define a different port; however, it must be within the range 1-65535 except for the following ports used by our core system: 15000, 15001, 15004, 15006, 15008, 15009, 15020, 15021, 15053, and 15090.
To configure a specific port for your application, click **Update port**, enter the new port, and click **Update.**
#### Disable HTTP(S) traffic
To disable all HTTP(S) traffic for your web process, click **Disable** > **Continue**.
### CDN & Edge caching
A [content delivery network (CDN)](/applications/cdn/) is crucial for modern hosting, and Kinsta provides a premium Cloudflare-powered CDN at no extra cost. Sevalla’s CDN delivers your site’s static assets through a global network spanning 260+ cities across more than 100 countries, ensuring faster content delivery to visitors worldwide.
[Edge caching](/applications/edge-caching/) takes this a step further by storing your site’s cached pages on Cloudflare’s global network of edge locations. When visitors access your site, cached content is served from the data center nearest to them. This minimizes latency, improves load times, and provides a faster, more consistent experience for users, no matter where they are in the world.
#### Enable CDN/Edge caching
To enable CDN or edge caching within Sevalla, click **Update settings**, and then select **CDN** and/or **Edge caching**.
#### Clear cache
Sevalla automatically purges the CDN and edge cache after every successful deploy, so updated content is served without any manual action in most cases.
To clear the CDN or edge cache, within **CDN & Edge caching**, click **Purge cache**. If both CDN and edge caching are enabled, purging the cache will apply to both.
Clearing edge cache in all of Cloudflare’s data centers may take 2-5 minutes to fully complete.
### IP restrictions
IP restrictions allow you to restrict or block access to specific IP addresses or CIDR blocks. If an unauthorized user (IP address) attempts to access the application, they will receive a **403 – Forbidden error**.
To change your IP restriction settings, click **Update IP Restrictions** and choose from the following:
* **No IP restrictions:** Allows all connections to your application.
* **IP allowlist:** Allows connections only from the specified IP addresses. When you select this option, enter the IP addresses or CIDR notations that should have access to your application. To add multiple entries, click the plus icon after each one. There is no limit to the number of entries.
* **IP denylist:** Blocks connections from specified IP addresses. When you select this option, enter the IP addresses or CIDR notations you want to block from accessing your application. To add multiple entries, click the plus icon after each one. There is no limit to the number of entries.
To save the changes, click **Update IP restrictions**.
### TCP proxy
You can connect **up tp three** processes over TCP using a proxied domain and port. This allows you to expose non-HTTP traffic, simplifying the deployment of services like [MongoDB](https://www.mongodb.com/) or [RabbitMQ](https://www.rabbitmq.com/) with public access. You can also use it to deploy a [Laravel app with Reverb](https://reverb.laravel.com/) (a WebSocket server) as a single application, with Reverb running as a background worker while still being publicly accessible.
To set up a TCP proxy, click **Create TCP proxy**, choose the **Process** you want to connect to via TCP proxy, enter the **Port** you want to use, and click **Create TCP proxy**.
Once the TCP proxy is added, a hostname is assigned to the process, which you can use to connect to it.
## Private networking
### Internal hostnames
This shows the hostname for all of the application processes. You can use the hostname to connect to the processes on Sevalla’s private network.
### Connected services
This shows any applications or databases that are connected to the current application over Sevalla’s private network.
Currently, internal connections are only supported between applications in the same region. If you’re deploying an application and a database, you must choose the same region for both.
### Add a private connection
You can add a private connection from an application’s **Networking** page or a database’s **Overview** page. Wherever you start the process, the result will be the same.
To add a connection from an application to another application or database, go to **Applications** > ***app name*** > **Networking** > in the **Connected services** section, click **Add internal connection**, and select the application or database you’d like to create the internal connection to.
#### Environment variables
We can automatically populate an application’s [environment variables](/applications/environment-variables) from the connection details. Do not copy and paste the internal connection details into environment variables. Click **Add connection** or **Add application** and select the **Add environment variables…** checkbox. This will automatically populate the environment variables from the application or database you’re connecting to.
Some applications may expect environment variables (keys) with different names. You can edit the names in the list before adding the connection or [**edit them later on the application’s Environment variables page**](/applications/environment-variables).
### Remove a private connection
If you need to remove a connection, go to the Application’s **Networking** page, and under **Connected services**, click the ellipsis (three dots) and click **Delete**.
### Private ports
You can expose a port internally to improve communication between applications. This is especially useful in microservice architectures or when running services like RabbitMQ or databases that require internal network accessibility.
To expose a port internally, click **Expose private port**, choose the **Process** you want to expose the port for, enter the **Port**, and click **Expose port**.
Sevalla automatically deploys your application when you expose a port.
# Applications - Overview
Source: https://docs.sevalla.com/applications/overview
Get a comprehensive overview Sevalla's Application Hosting.
Application hosting allows you to deploy applications from source code right onto the Sevalla infrastructure. You can also use [pipelines](/applications/get-started/pipelines) to fully automate this process and seamlessly push changes from your source code to QA and production environments without needing to rebuild the application.
Within the context of Sevalla's Application Hosting, an application is a set of instructions executed by a server to perform one or more tasks. Our current infrastructure is designed to serve and support the deployment of applications with a server behind the application.
For the best possible compatibility with our service, we recommend following the guidelines of [The Twelve-Factor App](https://12factor.net/) (aka Cloud-Native apps).
## Using a Dockerfile
You can deploy an application through Docker using a [Dockerfile](/applications/build-options/dockerfile), which means you can package any configuration you'd like, and we'll be able to run it for you.
## Templates
We have one-click [Templates](https://docs.sevalla.com/templates/overview) available for you to deploy and test in Sevalla, including AI, CMS, Storage applications, and more.
## Git service providers
When you [add an application](/applications/get-started/add-an-application), you can use a public or private Git repository or Docker image. If you use a public Git repository, you need the URL and branch of the repository. If you want to use a private Git repository, you'll need to select a Git service provider and repository from your account. You can choose from any (or all) of the following:
* [Bitbucket](/applications/git/bitbucket)
* [GitHub](/applications/git/github)
* [GitLab](/applications/git/gitlab)
## Docker images
When you [add an application](/applications/get-started/add-an-application), you can use a public or private Git repository or Docker image. If you use a public Docker image, you need the path to the Docker image. If you want to use a private Docker image, you must add your registry credentials within **Integration** > **Registry credentials**. You can choose from any (or all) of the following registries:
* GitHub (ghcr.io)
* GitLab (registry.gitlab.com)
* Docker Hub (docker.io)
## Pricing
Application Hosting is usage-based, so you only pay for the [resources your application uses](/applications/analytics), based on the following:
* Bandwidth (egress only)
* Build time
* Application hosting pod usage
For information about how we calculate these, refer to [Application Pricing](https://docs.sevalla.com/billing/application-pricing). To estimate your monthly costs before you deploy, use the [Sevalla pricing calculator](https://sevalla.com/pricing/calculator/).
## Important notes
Please keep the following in mind:
* During build time and runtime, your processes will have root access to their container. Our containers are isolated horizontally and vertically, providing sufficient protection even in this scenario. Regardless, root access is not advised, and we will likely remove that ability in the future, so please do not rely on having root access in the runtime environment of your application. You cannot install packages via root access.
## Troubleshooting
If you're having any trouble deploying your application, here are some important things to keep in mind and some troubleshooting tips:
* Pods and processes running within them are ephemeral, which means that they cannot be used in place indefinitely and cannot be used to store data such as uploaded images, videos, etc. Files related to user content should be stored in [persistent storage](/applications/storage) or third-party storage locations.
* If your application deployment fails during rollout, or your application fails to build, check out our guide for [Failed Deployment](/applications/troubleshooting/failed-deployment).
* If you need to pause your application while you troubleshoot errors, you can do so on the [Application Settings](/applications/settings) page (**Applications** > ***app name*** > **Settings** > **Suspend app**).
* Your application's runtime logs can be found on the Logs page (**Applications** > ***app name*** > **Logs**).
# Processes
Source: https://docs.sevalla.com/applications/processes
Learn about the different processes that make up your applications.
The **Processes** page within your application shows your runtime processes; here, you can add new processes, edit the resources for existing processes, and define your own runtime commands.
## Web process
The web process runs your application. When you [add an application](/applications/get-started/add-an-application), if you do not specify the Start command for the web process, Sevalla attempts to detect it automatically during the first deployment. For example, the start command for a Node.js application may be `npm start` or `yarn start`.
You cannot remove the web process, and you can only have **one web process per application**.
If you want to edit the port for your web process, you can do this within the application's Networking tab.
### Edit the web process
To edit the web process within **Processes**, click the ellipsis (three dots) and click **Update process**.
The following fields are available:
#### General
* **Name:** Your web process name.
* **Custom start command:** This is the start command for your web process. If you left this blank when adding the application, you should see the command that was automatically detected to run it.
* **Resource:** This determines the CPU and RAM dedicated to the process.
#### Scaling
* **Horizontal auto-scaling:** If you enable horizontal [auto-scaling](/applications/scalability), you need to define a minimum and maximum number of instances you want the web process to be able to use. When auto-scaling is enabled, if CPU or memory usage on the current pod(s) reaches its target (80% of the available CPU or memory by default, both adjustable), the web process will automatically increase by one, up to the maximum number you've set. If usage decreases and the current number of pod(s) is no longer needed, the number of pods will be reduced to what is needed. The instance count will not go lower than the minimum number you've set.
* **Instance count:** The number of instances required, up to a maximum of 20. Each instance represents one pod, and the instances all use the same pod size. You cannot define a different pod size for each instance.
#### Health checks
Health checks help ensure your application is running smoothly and can handle incoming traffic properly. There are two types of probes used to monitor the health of your process:
* **Readiness probe:** This probe determines whether the process is ready to receive traffic. If it fails, the process will not handle requests until it becomes healthy again.
* **Liveness probe:** This probe checks whether the process is still functioning correctly. If it fails, the process is automatically restarted to restore normal operation.
If you enable a health check probe, the following options are available:
* **Path:** Specify the path that should be used for the health check.
* **Port:** Specify the port that the health check should use. This is especially helpful in more advanced setups where your application exposes a dedicated health-check endpoint on a different port or uses custom health-check logic.
* **Initial delay:** The number of seconds to wait after the container starts before running the first probe.
* **Period:** How frequently the probe runs (in seconds).
* **Timeout:** The number of seconds to wait for a response before the probe times out.
* **Success threshold:** The minimum number of consecutive successful checks required for the process to be considered healthy after a failure.
* **Failure threshold:** The number of consecutive failed checks before the container is marked as unhealthy.
If you add persistent storage to your application's web process, it is limited to one instance. There is no horizontal scaling for processes with persistent storage, but you can vertically scale it by increasing the instance size for the process. You cannot add persistent storage or horizontal scaling to a cron job or job.
## Background worker
A background worker is a process that runs in the background, separate from the main application, and is inaccessible from the internet. Using a background worker for ongoing tasks like processing large data sets keeps these tasks separate from the main application and helps to maintain a good user experience.
This type of process isn't meant to be run as a one-time job that finishes after a certain amount of time. If a background process finishes after it completes its job, the pod will shut down, restart itself, and repeat the process. For a process that finishes after completing its job, use a [cron job process](#cron-job-process).
### Add a background worker process
You can add a background worker within **Processes**. While there is no limit to the number of background worker processes you can add, each process requires at least one pod to run.
To add a new background worker, click **Create new process** > **Background worker** and complete the fields as follows:
#### General
* **Name**: The process name. By default, this is populated with three random words.
* **Custom start command**: The command required to start the process, for example, npm run \[process].
* **Resource:** This determines the CPU and RAM dedicated to the process.
#### Scaling
* **Horizontal auto-scaling:** If you enable horizontal [auto-scaling](/applications/scalability), you need to define a minimum and maximum number of instances you want the background process to be able to use. When auto-scaling is enabled, if CPU or memory usage on the current pod(s) reaches its target (80% of the available CPU or memory by default, both adjustable), the background process will automatically increase by one, up to the maximum number you've set. If usage decreases and the current number of pod(s) is no longer needed, the number of pods will be reduced to what is needed. The instance count will not go lower than the minimum number you've set.
* **Instance count:** The number of instances required, up to a maximum of 20. Each instance represents one pod, and the instances all use the same pod size. You cannot define a different pod size for each instance.
Click **Create process** to finish creating the new process. The additional process costs are added to your monthly invoice and are prorated for the first month. For example, if you add a background worker with the S1 instance (0.5 CPU / 1 GB RAM) on January 20th, you'll be charged for 11 days in January: $20 / 31 * 11 = $7.10.
If you add persistent storage to your background workers, it is limited to one instance. There is no horizontal scaling for processes with persistent storage, but you can vertically scale it by increasing the pod size for the process. You cannot add persistent storage or horizontal scaling to a cron job or job.
You can change the details of any process at any time, including the instance size (vertical scaling) and the number of instances running simultaneously (horizontal scaling). To learn more, refer to [Scalability](/applications/scalability).
## Cron job process
A cron job allows you to schedule a process at a specific interval for your application. This lets you automate repetitive tasks like sending reports or performing maintenance tasks in a timed manner without a continuously running pod.
A cron job process is similar to a [background worker](#background-worker), but it only launches based on the configured timing and shuts down after finishing the required operation.
Laravel cron jobs must be run as a [background worker](#background-worker) with the start command `php artisan schedule:work`.
### Add a cron job process
You can add a cron job within **Processes**. While there is no limit to the number of cron job processes you can add, each process requires at least one pod to run.
To add a new cron job, click **Create new process** > **Cron job** and complete the fields as follows:
* **Name**: The process name. By default, this is populated with three random words.
* **Custom start command**: The command required to start the process, for example, npm run \[process].
* **Schedule**: Determines when and how often the cron job runs. This must be entered as an expression. It is made up of the following five fields:
* `*` Minute (0-59)
* `*` Hour (0-23)
* `*` Day of the month (1-31)
* `*` Month (1-2)
* `*` Day of the week (0-6) There is a lot of support available online about how to format your expression, such as [Cronitor](https://crontab.guru/#*/30_*_*_*_*). The following are some common examples of how to format your expression:
* To run the cron job every minute, use `* * * * *`
* To run the cron job every 30 minutes, use `*/30 * * * *` note that `*/30` ensures the process runs every 30 minutes (12:00, 12:30, etc.); if you use `30` without the `*/` it will only run at minute 30 (12:30, 13:30, etc.).
* To run the cron job every hour, use `0 * * * *`
* To run the cron job every day at 12:00 AM, use `0 0 * * *`
* To run the cron job at 12:00 AM, on Fridays only, use `0 0 * * 5`
* To run the cron job at 12:00 AM on the first day of every month, use `0 0 1 * *`
* **Set custom time zone:** The default time zone for cron jobs is Coordinated Universal Time (UTC). If you want your cron job to run at a specific time in your own time zone, select this option and define your time zone. This uses the [IANA time zone identifier](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). For example, if you want to set this to New York, you must enter America/New\_York.
* **If the previous run is still active (concurrency policy)**: Determines what happens when a run is scheduled while the previous run is still going:
* **Skip the new run** (default): Skips the new run until the current one finishes.
* **Replace the running job**: Cancels the currently running job and starts a new one. Use this if a stuck run should not block future runs; the stuck run is cleared at the next scheduled run.
* **Max run time**: The maximum time in seconds each scheduled run may take. If a run exceeds this limit, it is terminated. Leave this empty or set it to `0` for no limit.
* **Resource**: This determines the CPU and RAM dedicated to the process.
The concurrency policy and max run time are also available through the API as `concurrency_policy` and `active_deadline_seconds` on [Create process](https://api-docs.sevalla.com/v3/applications/create-process) and [Update process](https://api-docs.sevalla.com/v3/applications/update-process). They apply to cron processes only.
The concurrency policy and max run time are also available through the API as `concurrency_policy` and `active_deadline_seconds` on [Create process](https://api-docs.sevalla.com/v3/applications/create-process) and [Update process](https://api-docs.sevalla.com/v3/applications/update-process). They apply to cron processes only.
Click **Create process** to finish creating the new process. The additional process costs are added to your monthly invoice, and you are only charged for the time the process is running. For example, if you add a cron job with the S1 instance (0.5 CPU / 1 GB RAM) and it runs for 60 minutes in a month, 3600 seconds \* 0.0000076104 (price per second) = \$0.03.
You can change the details of any process at any time, including the instance size (vertical scaling). You cannot add [persistent storage](/applications/storage) or [horizontal scaling](/applications/scalability) to cron jobs.
## Job process
A job allows you to run a one-off process for your application either before deployment, after a successful deployment, or after a failed deployment. This can be useful for sending alerts or performing database migrations in a separate process rather than appending your migration script to your web process start command.
A job only launches based on the configured start policy and shuts down after finishing the required operation.
### Add a job process
You can add a job within **Processes**. While there is no limit to the number of job processes you can add, each process requires at least one pod to run.
To add a new job, click **Create new process** > **Job** and complete the fields as follows:
* **Name**: The process name. By default, this is populated with three random words.
* **Custom start command**: The command required to start the process, for example, npm run \[process].
* **Start policy**: Choose when to start the process, either **Before deployment**, **After successful deployment**, or **After failed deployment**.
* **Resource**: This determines the CPU and RAM dedicated to the process.
Click **Create process** to finish creating the new process. The additional process costs are added to your monthly invoice, and you are only charged for the time the process is running. For example, if you add a job with the S1 instance (0.5 CPU / 1 GB RAM) and it runs for 60 minutes in a month, 3600 seconds \* 0.0000076104 (price per second) = \$0.03.
You can change the details of any process at any time, including the instance size (vertical scaling). You cannot add [persistent storage](/applications/storage) or [horizontal scaling](/applications/scalability) to jobs.
## Defining processes in a Procfile
Procfiles define processes from your application's code, which should be committed to your repository. A Procfile contains one process per line in the following format:
```text theme={null}
process_name: command
```
For example, to run a Laravel application, you might want to use the following:
```text theme={null}
web: php artisan serve --host 0.0.0.0 --port 8080
```
If you are using a Procfile, you will need to define a process named **web** to ensure the container will fulfill web requests.
We will likely deprecate the usage of Procfiles in the future as we prefer a more standardized way of describing deployments, which would be possible through JSON or YML files.
## Scaling application resources
You can change the pod size of any process (vertical scaling) and the number of pods that run at the same time (horizontal scaling) for the web process and background workers.
If you add persistent storage to a web process or background worker, they are limited to one instance. There is no horizontal scaling for processes with persistent storage, but you can vertically scale them by increasing the pod size for the process. You cannot add persistent storage to a cron job or job.
* Vertical scaling is great for giving pods more power to complete resource-intensive tasks.
* Horizontal scaling is great for resilience and load balancing for applications that process many requests. For example, you could run three versions of the same pod. The underlying technology routes requests to one of the three pods, effectively distributing the load between them. If one pod becomes unstable, requests will route to the other two until the third pod is healthy again.
You can change the details of any process, including the **Resource**, at any time. If your application is stateless (no persistent storage), you can enable [automatic horizontal scaling](/applications/scalability) for the web process or background worker. This lets you set a minimum and maximum number of instances (up to 10) that the process can scale between as needed. To learn more about changing pod size and other scaling options, see [Scalability](/applications/scalability).
# Applications - FAQs
Source: https://docs.sevalla.com/applications/reference/faqs
Find answers to frequently asked questions about application hosting.
Below we’ve compiled the most common technical questions about Sevalla’s [Application Hosting](https://sevalla.com/application-hosting/).
## What kind of repository can I use with Application Hosting?
When you [add an application](/applications/get-started/add-an-application) in Sevalla you can use a public or private [Git repository](/applications/git/overview) or [Docker image](/applications/docker-images).
If you use a public Git repository, you need the URL and branch of the repository. Private Git repositories must be hosted on [Bitbucket](/applications/git/bitbucket), [GitHub](/applications/git/github), or [GitLab](/applications/git/gitlab).
If you use a public Docker image you need the path to the Docker image. Private Docker images must be hosted on a GitHub (ghcr.io), GitLab (registry.gitlab.com), or Docker Hub (docker.io) registry.
## Can I save data to the file system?
Yes, if you add [persistent storage](/applications/storage), which adds a storage volume that retains data even if the application is restarted or redeployed.
## Can I move or clone an application to a different region?
An application's region (data center) is set when you [add the application](/applications/get-started/add-an-application) and can't be changed in place. To run an application in a different region, clone it into the target region instead of recreating it by hand.
The Sevalla API's clone endpoint creates an identical copy of an existing application, including its processes, environment variables, build settings, and configuration, then triggers an initial deployment automatically. To clone into another region, send a `POST` request to `/applications/{id}/clone` with a `display_name` and the `cluster_id` of the target region:
```bash theme={null}
curl -X POST https://api.sevalla.com/v3/applications/{id}/clone \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"display_name": "My App (europe-west1)", "cluster_id": "TARGET_CLUSTER_ID"}'
```
This is the easiest way to co-locate an application with its database, since [internal connections](/applications/networking) are only supported between applications and databases in the same region. You can list the available regions and their cluster IDs with the `/resources/clusters` endpoint. For full details, see the [API reference](https://api-docs.sevalla.com/).
Persistent storage contents and the temporary `.sevalla.app` domain are not carried over to the clone. After the clone is deployed, set up the internal connection to your database and move any custom domains, then delete the original application.
## Can I host (insert your preferred CMS or framework) with Sevalla’s Application Hosting?
There’s a good chance the answer is yes.
If you’re not sure, feel free to give it a try! Our [Support team](/support/contact-support/) will work with you to help with any bugs you encounter on our platform, though we cannot guarantee all applications will work.
## Can applications send email?
Yes, if your application uses a service like SendGrid or Mailchimp to send emails through their API. Ports 25, 465, and 587 (standard SMTP ports) are blocked at Sevalla because we do not provide email hosting services.
## Can I get a static external IP address to add my application to an allowlist with third-party services?
Because the IP address of your application may change/rotate with each deployment, it isn’t possible to provide a single specific outbound IP address. We recommend using a different authorization method (e.g. OAuth, a bastion server, etc.) to authenticate your application with your third-party service.
If your third-party service only supports IP-based allowlisting (for example [MongoDB Atlas](https://www.mongodb.com/atlas) or some email providers), you can allowlist the IP ranges of the underlying infrastructure instead of a single address. Sevalla runs on Google Cloud, which publishes its full list of IP ranges at [https://www.gstatic.com/ipranges/cloud.json](https://www.gstatic.com/ipranges/cloud.json).
Each entry in that file has a `scope` field set to a region. Scope the list down to the region your application is deployed to, then allowlist the matching `ipv4Prefix` (and `ipv6Prefix`) ranges. For example, an application deployed to `australia-southeast1` would use only the ranges where `"scope": "australia-southeast1"`.
To extract the IPv4 ranges for a region with `curl` and `jq`:
```bash theme={null}
curl -s https://www.gstatic.com/ipranges/cloud.json \
| jq -r '.prefixes[] | select(.scope == "australia-southeast1") | .ipv4Prefix | select(. != null)'
```
These ranges are shared across all Google Cloud workloads in the region, so they are much broader than your application alone, and Google updates the published list periodically. Re-check it regularly and prefer credential-based authentication (such as an API key or SMTP username and password) whenever your service supports it.
## Can you specify the Python version and module version?
Yes, you can specify the Python version in your application’s **runtime.txt** file:
```text theme={null}
python-3.10.6
```
The module version can be specified in the **requirements.txt** file:
```text theme={null}
Django==3.2
virtualenv==20.18.0
```
For more examples in other languages, refer to specify a Language Version in Nixpacks or Buildpacks.
## Can I run Composer?
Yes, you can use Composer to declare the libraries and dependencies your project needs, and Composer automatically handles downloading, installing, and updating those dependencies. You can define the required dependencies for your project in a `composer.json` file in your project’s root directory. For more information, check out our blog post on [How to create your own Composer package](https://kinsta.com/blog/create-composer-package/).
## Can I define PHP extensions?
Yes, you can specify the required PHP extensions in your `composer.json` file to ensure that the necessary extensions are installed and enabled for your application to work correctly. For example, if you want to use the Imagick extension from [ImageMagick](https://imagemagick.org/) for image processing, you can add the following to `composer.json`:
```text theme={null}
{
"require": {
"ext-imagick": "*"
}
}
```
# Applications - Glossary
Source: https://docs.sevalla.com/applications/reference/glossary
Look up important terms and definitions related to application hosting.
## Add-On
A recurring/ongoing service that isn't a [hosting service](https://sevalla.com/pricing/); for example, the [database disk space add-on](/billing/database-pricing#database-disk-space-add-on) or [persistent storage](/applications/storage).
## Application
Within the context of Sevalla's Application Hosting, an application is a set of instructions executed by a server to perform one or more tasks. Our current infrastructure is designed to serve and support the deployment of applications with a server behind the application.
## Application Hosting
One of Sevalla's [Hosting Services](https://sevalla.com/pricing/). It is a Platform as a Service (PaaS) that provides you with the tools you need to deploy applications from a Git repository.
## Artifact registry
The location where built images are stored. Each application has a single image that can be turned into a container.
## Automatic deployment
When Automatic deployment on commit is enabled, and a new commit is made to the default branch of your Git repository, a new version of the application will be deployed from Sevalla.
## Background worker
A process that runs in the background, separate from the main application, and is inaccessible from the internet. Used to keep long-running processes separate from the main application to help maintain a good user experience. Not meant to be run as a one-time job that finishes after a certain amount of time. If a background process finishes after it completes its job, the pod will shut down, restart itself, and repeat the process. For a process that finishes after completing its job, use a [cron job process](/applications/processes#cron-job-process).
## Build time
The time it takes for an image to be built from an application's source code. Builds are performed on machines specifically designated for building images. Multiple build machine sizes exist, and you can choose between these machines depending on the resources required to build the application. Build time is billed at different rates, separate from your [application's hosting pods](/billing/application-pricing).
## Buildpack
Buildpacks are scripts that run when an application is deployed. They are used to install dependencies for your application and configure your environment.
## Commit
A commit records changes to one or more files in a Git branch and assigns a unique ID (called an SHA or hash) that identifies the specific changes and when those changes are made.
## Concurrent builds
With free unlimited concurrent builds in [Sevalla's Application Hosting](https://sevalla.com/application-hosting/), you can start as many builds as you want, in as many different applications as you want, all at the same time. You are not limited to a set number of builds per application or account, and there's no additional charge for concurrent builds.
That means you can simultaneously start a build in one application, switch to and start a build in another application, or add a completely new application, all without waiting for other builds to finish.
## Concurrent connections/users
Concurrent connections are connections that are happening simultaneously (i.e. at the same time). While there is a relationship between concurrent connections and users, it is not always a direct 1:1 relationship. One user can spawn multiple connections, depending on their actions and depending on the application's code.
An application's maximum concurrent connections depends on a number of factors, including its code, usage patterns of users, etc. To calculate this number, you need to know your application's resource consumption. There are a number of [load testing tools](https://kinsta.com/blog/performance-testing-tools/#1-load-testing) you can use to send concurrent connections to the application and see the resource usage during that time:
* [Apache JMeter](https://jmeter.apache.org/)
* [AutoCannon](https://www.npmjs.com/package/autocannon)
* [Artillery](https://www.artillery.io/)
## Connection
Connections are how applications communicate.
An **External connection** allows your database to communicate with an external application. This would be used in a situation where you are hosting only your database with us but not the frontend of your application. Because an external connection makes an internet round-trip, it is much slower than an internal connection.
An **Internal connection** stays within our network and is thus much faster and more secure. We recommend this method if you host both your frontend and your database with Sevalla.
## Cron job
A process you can schedule at a specific interval once a day, once a month, every 10 minutes, etc) so you can automate repetitive tasks for your application. The process only launches based on the configured timing and shuts down after finishing the required operation.
## Database
A collection of data that is stored in an organized manner so it can be retrieved or updated efficiently. You can choose from a number of database types with Sevalla's [Database Hosting](https://sevalla.com/database-hosting/) service.
## Deployment
A deployment is a rebuild of your application in a new container, usually done after updating your application's code, but can be configured to happen automatically (see automatic deployment above). The deployment invokes any buildpacks and applies any [environment variables](/applications/environment-variables) each time the application is deployed.
## Environment variables
Variables such as API keys, database connection details, or other configuration values or secrets. By using [environment variables](/applications/environment-variables), you can avoid putting this information in your code as cleartext (unencrypted text).
## Ephemeral
Services, pods, applications, containers, etc., that do not exist indefinitely and cannot be used to store data like uploaded images, videos, etc. Data that is part of the application itself (a favicon or logo, etc.) can be stored in ephemeral locations because when the application is rebuilt, its data is put back in place when the application is deployed.
Ephemeral containers provide resilience. Multiple versions of a pod can be launched, and if needed, new pods can be launched without the application suffering downtime.
## Git repository
A Git repository is where your application's code and historical versions of that code are saved.
## Hosting services
Sevalla's services that allow you to host specific types of content:
* [Application Hosting](https://sevalla.com/application-hosting/)
* [Database Hosting](https://sevalla.com/database-hosting/)
* [Static Site Hosting](https://sevalla.com/static-site-hosting/)
Other services include [add-ons](#add-on) like the [database disk space add-on](/billing/database-pricing#database-disk-space-add-on) or [persistent storage](/applications/storage).
## Image
An image is the result of the building process from the application code. [Pods](#pod) are created based on Images.
## Instance
See [Pod](#pod) below.
## Logs
Runtime logs from the application build process.
## Monorepo
A software development strategy where code for several projects is stored in the same repository. To use a monorepo with [Application Hosting](https://sevalla.com/application-hosting/), you must specify the **Build path** in **Settings** > **Build strategy > Update build strategy**.
## Sevalla company
A company is an organizational unit within Sevalla. Each company can have multiple users of various roles associated with it but can only have one owner. A company can have multiple applications, databases, or static sites.
## Node
A node is a virtual machine that houses [pods](#pod).
## Overages
If you use more than the included resources, you incur overages. Our [Application Hosting](https://sevalla.com/application-hosting/pricing/) and [Database Hosting](https://sevalla.com/database-hosting/pricing/) do not incur overages because they are usage-based, and you only pay for the resources your application or database uses.
## Persistent storage
[Persistent storage](/applications/storage) (aka persistent volume) retains data after an application is shut down or restarted. It's used for data that needs to be preserved across multiple sessions or devices, such as session data, user preferences, and cached content.
Stateful applications use persistent storage to request storage volume from an underlying storage system. The storage volume is mounted as a file system, which allows the application to read or write to the storage device as if it were a local disk.
## Pod
A Pod is a container that runs a [Process](/applications/processes). Each Pod has a **Pod Size** that defines the resources available to the Pod in terms of processor cores (CPU) and memory (RAM). Depending on the Process in the Pod, you may want to [increase or decrease the resources](/applications/scalability) to run applications more efficiently.
## Pod scaling
The ability to [increase the resources available to a pod](/applications/scalability) (vertical scaling) or increase the number of pods (horizontal scaling) that run the same [Process](/applications/processes) to ensure high availability and load balancing.
## Pod size
Pod size determines the number of processor cores (CPU) and memory (RAM) available to the pod. Depending on the process the pod is running, you may want to increase or decrease the resources to run the application efficiently.
## Postpaid
Postpaid services are paid for after the service is received. Utility bills are a common example where normally you pay after services have been rendered, receiving the amount used and the price in an invoice. Sevalla's [Application Hosting](https://sevalla.com/application-hosting/pricing/) and [Database Hosting](https://sevalla.com/database-hosting/pricing/) services are postpaid. You pay only for the resources used at the end of each monthly billing cycle. These services are prorated to the second and postpaid.
## Process
The smallest unit you can deploy in our Application Hosting. While this is usually a well-defined item, like a frontend for a web application, it could also serve as the backend for a mobile application. While it is usually well-defined, it's up to you to decide what you want to run within a Pod or what constitutes a process. It's possible to run multiple processes within a pod, but the Pod's resources will be split up among those processes.
## Start command
The command required to start your application is called the start command for applications built with a buildpack. If you use a [Dockerfile](/applications/build-options/dockerfile) to create your container image, you must specify the `ENTRYPOINT` or `CMD` in your Dockerfile.
## Static Site Hosting
[Static Site Hosting](/static-sites/overview) is a service that allows you to host static websites for free. These websites are built using HTML, CSS, and JavaScript and do not require a server-side language like PHP or a database like MySQL.
## Usage-based pricing
Usage-based pricing means that you only pay for the [resources used](/applications/analytics/). For [Application Hosting](https://sevalla.com/application-hosting/) and [Database Hosting](https://sevalla.com/database-hosting/), we bill monthly at the end of your billing cycle or when your use of the services reaches a preset billing threshold, whichever occurs first.
## Virtual Machines
Virtual Machines (VMs) emulate completely separate servers and can hold multiple containers and multiple databases. At Sevalla, our [infrastructure](/applications/get-started/infrastructure) includes VMs built on high-performance, enterprise-grade servers.
# HTTP headers
Source: https://docs.sevalla.com/applications/reference/http-headers
Reference for HTTP headers supported by the platform.
HTTP headers are strings of `name:value` pairs (name and value separated by a colon) that are used to communicate additional information and metadata between a client (usually a web browser) and an application on a server. This information may include how data is encoded, how the server should handle data, the document’s age, and more.
Response headers (from the application to the client) are part of the application’s response and may contain information like the server location, server name, etc.
Request headers (from the client to the application) are helpful if you want to customize your application. A few examples are:
* Reporting different types of content per the client region using `CF-IPCountry`.
* Using `CF-Connecting-IP` to record the client IP in the application’s activity log.
* Performing debugging or monitoring user sessions using `X-Request-ID`.
## Request headers added by Sevalla
When you [deploy an application on Sevalla](/applications/get-started/add-an-application), the following headers are used to send information to the application:
* `Host`: The host header specifies the hostname and port number of the server that is being requested.
* `X-Request-ID`: Used to identify a request between the client and the server. This header can be useful for debugging purposes.
* `X-Real-IP`: Specifies the real IP address of the client that made the request. This header is commonly used by reverse proxies and load balancers to indicate the original client IP address.
* `X-Forwarded-For`: Used to specify the client’s IP address and can also contain a list of IP addresses if the request passes through multiple proxies.
* `X-Forwarded-Host`: Specifies the original host requested by the client.
* `X-Forwarded-Port`: Specifies the port used by the client to make the request.
* `X-Forwarded-Proto`: Specifies the protocol the client uses to make the request, such as “HTTP” or “HTTPS.”
* `X-Forwarded-Scheme`: Specifies the scheme the client uses to make the request, such as “HTTP” or “HTTPS.”
* `X-Scheme`: The header is similar to `X-Forwarded-Scheme`, and is used to indicate the original scheme requested by the client.
* `X-Original-Forwarded-For`: Specifies the original client IP address in a request that has passed through multiple proxies.
* `Accept-Encoding`: Specifies the encoding types that the client can accept in the response, such as `gzip` or `deflate`.
* `CF-Ray`: A unique identifier generated by the Cloudflare service for each request.
* `CF-Visitor`: Used by Cloudflare to transmit information about the client’s browser and device to the server.
* `CF-EW-Via`: Used by the Cloudflare Edge Workers service to indicate that an Edge Worker processed a request.
* `CDN-Loop`: Used by some content delivery networks to indicate that a request is stuck in a loop and needs to be terminated.
* `Accept`: Specifies the media types that the client can handle in the response, such as `text/html` or `application/json`.
* `User-Agent`: Specifies the client’s user agent string, which can be used to identify the client’s browser and operating system.
* `CF-Connecting-IP`: Specifies the IP address of the client that is connecting to the server through the Cloudflare network.
* `CF-Worker`: Used to indicate that a Cloudflare worker processed a request.
* `CF-IPCountry`: Specifies the country code of the client’s IP address, as determined by Cloudflare.
## Viewing request headers
While response headers can be viewed with tools like [Sevalla’s HTTP Status and Redirect Checker](https://kinsta.com/tools/redirect-checker/), `curl`, Postman, Insomnia, etc., viewing request headers is a bit different. To view request headers, you can use your application’s code to see and report the headers sent to it. Here’s an example of this using Python:
```
from http.server import BaseHTTPRequestHandler, HTTPServer
import loggingclass RequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
logging.info("GET request,nPath: %snHeaders:n%sn",
str(self.path), str(self.headers))
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
message = f"{self.headers}"
self.wfile.write(bytes(message, 'utf-8'))
returndef run(server_class=HTTPServer, handler_class=RequestHandler, port=8080):
logging.basicConfig(level=logging.INFO)
server_address = ('', port)
httpd = server_class(server_address, handler_class)
logging.info('Starting httpd...n')
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
logging.info('Stopping httpd...n')if __name__ == '__main__':
from sys import argvif len(argv) == 2:
run(port=int(argv[1]))
else:
run()
```
# Runtime and access logs
Source: https://docs.sevalla.com/applications/runtime-logs
Access real-time logs for your applications.
On the **Logs** page, you can view your application’s runtime and access logs up to the last 30 days. Click on the ellipsis (three dots) to refresh your log data, download your logs as a JSON or CSV file, copy the logs, and access the keyboard shortcuts.
## Runtime logs
You can filter the runtime logs by severity, process, or create your own custom filter. When you add a custom filter, click **Run query** to apply it.
## Access logs
To view the access logs, click **Runtime logs** and then select **Access logs**. You can search the logs and create your own custom filter. When you add a custom filter, click **Run query** to apply it.
## Deployment runtime logs
You can view the runtime logs for each individual deployment within **Deployments** > select the required deployment > **Runtime logs**.
# Scalability
Source: https://docs.sevalla.com/applications/scalability
Learn how to scale your applications efficiently on the platform.
You can scale an application's resources by changing the instance size (vertical scaling) or increasing the number of instances that simultaneously run your application (horizontal scaling).
If you add persistent storage to your application's web or background processes, those processes are limited to one instance each. There is no horizontal scaling for web or background processes with persistent storage, but you can vertically scale them by increasing the instance size for the process. You cannot add persistent storage or horizontal scaling to a cron job or job.
* **Vertical scaling** gives instances more power to complete resource-intensive tasks.
* **Horizontal scaling** improves resilience and load balancing for applications that process many requests. For example, if you run three versions of the same instance, the underlying technology routes requests to one of the three instances, effectively distributing the load between them. If one instance becomes unstable, requests will route to the other two until the third instance is healthy again.
## Manual scaling
To change the instance size of a process, go to **Applications >** ***app name*** **> Processes**. Click the ellipsis > **Update process**.
Update the **Resource** to increase the resources available to a single instance (vertically scale), or update the **Instance count** within **Scaling** to add instances and improve the load balance (horizontally scale). There is a maximum of 20 instances, and all instances use the same size.
**Note:** If you choose the **Hobby** instance size for your web process, you will **not** be able to [add a custom domain to your application](/applications/domains/). If you need a custom domain for your application, you can upgrade your web process to a larger instance size anytime.
Once you have made your changes, click **Update process**. The updated process costs are added to your monthly invoice and are prorated for the first month.
## Automatic horizontal scaling
Horizontal auto-scaling can be enabled for a **stateless** web process or background worker within **Processes** (**Applications >** ***app name*** **> Processes**). When you enable horizontal auto-scaling, you'll define a minimum and maximum number of instances you want the process to use. **Note:** The maximum number of instances cannot exceed 20.
When horizontal auto-scaling is enabled, the process automatically increases by one instance, up to the maximum number you've set, whenever CPU or memory usage on the current instance(s) reaches its target. By default the target is 80% of the instance's available CPU and memory, and you can adjust the CPU and memory targets when you configure auto-scaling.
If CPU and memory usage drop and fewer instances are required, the system automatically scales down the number of instances to match current demand. However, it will never reduce the count below the minimum number of instances you’ve configured for horizontal auto-scaling.
While there currently isn't a way in Sevalla to see how many instances are in use, behind the scenes, only the number of instances needed will be used. You will only be [billed for the number of instances](/billing/application-pricing) your application actually uses. For example, if the minimum instance is set to one and the maximum is set to five, but the application only uses one instance during the billing period, you will only be charged for that one instance. If the application uses more instances for part of the time during the billing period, you will only be billed for those additional instances for the time they are actually used.
# Applications - Settings
Source: https://docs.sevalla.com/applications/settings
Change your application's settings and preferences.
On your application's **Settings** page, you can find details about your application, manage settings like buildpacks, and suspend or delete it.
## General
### Details
This section shows the application display name, name, and ID. To change the display name, click **Update display name**, enter a new name, and click **Update display name**.
### Hibernation
Hibernation automatically scales down your application if no HTTP requests are received within the specified timeframe. When traffic resumes, the application wakes up in 8-20 seconds, with the HTTP request remaining pending during that time. Cron jobs and other jobs continue to run normally, even while hibernation is active. To enable hibernation on your application, click **Update hibernation**.
Select **Hibernation**, enter the number of idle minutes after which you want your application to enter hibernation, and click **Update hibernation**.
## Deploy
### Source
This shows the information about the application source. The information shown depends on whether you use a Git repository or a Docker image.
#### Git repository
* **Source type:** Shows if the repository is private or public.
* **Git type:** Shows which Git provider the application is using.
* **Repository:** The Git repository.
#### Docker image
* **Source type:** This shows that the application is using a Docker image.
* **Docker image:** This is the path to your Docker image.
* **Registry credential:** This shows the name of the registry credentials set up within **Integration** > **Registry credentials**.
To change any of the details, click **Update source**.
### Auto-deploy
Use this option to automatically deploy each time a commit is made to the selected branch.
To enable or disable automatic deployments or change the branch to automatically deploy from, click **Update auto-deploy**. Select the required options and click **Update auto-deploy**.
### Deploy hook
Deploy hooks allow you to effortlessly trigger deployments by making a simple POST request to a unique URL, enabling seamless workflow integration.
To set up a deploy hook, click **Enable** and then click **Continue**. This generates a unique URL that you can call with a POST request to trigger a deployment. If you want to automate deployments based on external events (e.g., pushing code to a repository), you can configure a webhook in your repository provider (GitHub, GitLab, Bitbucket, or Docker) to call the deploy hook URL.
### Deploy paths
Deploy paths allow you to trigger deployments based on a specific set of rules. You can define which file changes should initiate a deployment and which should be ignored. For example, you can trigger deployments only when files in `/src/backend/**` are modified or skip deployments if changes are limited to `**/*.md` files. This can be especially useful for monorepos.
This feature is only available for applications with a private GitHub or GitLab repository. It is not available for Bitbucket repositories or Docker images.
To configure deploy paths, click **Update deploy paths**.
To trigger a deployment when a file is changed within a specific path, select **Allow paths**. To skip a deployment when a file is changed in a specific path, select **Ignore paths**. Add the required path patterns and click **Update deploy paths**.
### Git Large File Storage (LFS)
If your repository tracks files with [Git LFS](https://git-lfs.com/), Git LFS support ensures the actual file contents are fetched when the repository is cloned for a build. When disabled, LFS pointers are checked out as-is and the underlying objects are not downloaded.
Git LFS is enabled by default. The current state is shown as a **Git LFS enabled** or **Git LFS disabled** badge. To change it, click **Enable** (or **Disable** if it is already on), then click **Continue**. The change takes effect on the next deployment.
Git LFS is only available for applications deployed from a Git repository, not from a Docker image.
## Build
### Build strategy
This shows information about your environment's build strategy. To change any of these settings, click **Update build strategy**, and select from the following:
#### Nixpacks
Use [Nixpacks](/applications/build-options/nixpacks) to create a container for your application based on your repository.
* **Cache enabled:** When you build your application, Sevalla creates a deployable image from your code. By default, cache is enabled, which stores the latest successful deployment so that future builds can reuse unchanged components, significantly speeding up the process and reducing resource usage.
* **Build path:** This is the path in the repository to the files required to build the application. Most applications are built from the repository root, and the **Build path** defaults to this (.). If you have a different build path, specify it here. For example, if your application needs to be built from a subdirectory named **app**, enter **app** in the **Build path** field. This is also useful if you have a [monorepo](/applications/reference/glossary#monorepo).
* **Nixpacks version:** Choose the Nixpacks version you want to use to build your application. Different versions can affect the build process, so it’s important to review the [Nixpacks changelog](https://github.com/railwayapp/nixpacks/releases) for your application’s language. Ensuring compatibility is your responsibility, as changes between versions may impact how your application is built and runs.
#### Railpack
Use [Railpack](/applications/build-options/railpack), the successor to Nixpacks, to create a container for your application based on your repository. Railpack analyzes your repository and builds an optimized container image with zero configuration, powered by BuildKit.
* **Cache enabled:** When you build your application, Sevalla creates a deployable image from your code. By default, cache is enabled, which stores the latest successful deployment so that future builds can reuse unchanged components, significantly speeding up the process and reducing resource usage.
* **Build path:** This is the path in the repository to the files required to build the application. Most applications are built from the repository root, and the **Build path** defaults to this (.). If you have a different build path, specify it here. For example, if your application needs to be built from a subdirectory named **app**, enter **app** in the **Build path** field. This is also useful if you have a [monorepo](/applications/reference/glossary#monorepo).
#### Buildpacks
Use [Buildpacks](/applications/build-options/buildpacks) to create a container for your application based on your repository.
* **Cache enabled:** When you build your application, Sevalla creates a deployable image from your code. By default, cache is enabled, which stores the latest successful deployment so that future builds can reuse unchanged components, significantly speeding up the process and reducing resource usage.
* **Build path:** This is the path in the repository to the files required to build the application. Most applications are built from the repository root, and the **Build path** defaults to this (.). If you have a different build path, specify it here. For example, if your application needs to be built from a subdirectory named **app**, enter **app** in the **Build path** field. This is also useful if you have a [monorepo](/applications/reference/glossary#monorepo).
* **Pack builder:** Choose which buildpack builder you want to use. For information about what each builder includes, refer to [Heroku stacks](https://devcenter.heroku.com/categories/stacks).
* **Add buildpack:** Add the required buildpacks for your application. The buildpack that contains the primary language of your application must be the last one in the buildpacks list. For example, if you have a Node.js application and need to add another buildpack, make sure the Node.js buildpack is at the end of the list.
#### Dockerfile
Use a [Dockerfile](/applications/build-options/dockerfile) (stored in your repository) to create a container for your application.
* **Cache enabled:** When you build your application, Sevalla creates a deployable image from your code. By default, cache is enabled, which stores the latest successful Docker image so that future builds can reuse unchanged components, significantly speeding up the process and reducing resource usage.
* **Dockerfile path:** This is the path to your Dockerfile relative to the repository root. For example, if your Dockerfile is in the repository root, enter **Dockerfile** in that field. If your Dockerfile is in a subdirectory named **app**, enter the path to the Dockerfile: **app/Dockerfile**.
* **Docker context:** This is the path in the repository we need access to so we can build your application. Most applications are built from the repository root, and you can enter the repository root (**.**) in the **Context** field. For example, if your application needs to be built from a subdirectory named **app**, enter **app** in the **Context** field.
* **Docker Registry Credential:** This is only required for private Docker images. You must enter your registry credentials within **Integration** > **Registry credentials**. Once you've entered your credentials in the Company settings, you can choose which credentials you want to use.
If you change the environment, you must manually deploy your application again, which you can do on the [Deployments page](/applications/deployments/).
## Danger zone
Only Company Owners and Company Administrators can suspend, resume, or delete an Application. For information about how to change a user's access, refer to User Management.
### Suspend or Activate app
There may be times when you need to stop an application without deleting it. This can be useful if you need to troubleshoot issues or test parts of the application without it running.
Suspending the application doesn't change or remove anything from it. Connections to the application remain in place but will not work while the application is suspended. You will not incur any costs for the application during the suspension.
Click **Suspend app** and confirm the suspension by clicking **Continue**.
When you're ready to restart your application, click **Activate app** and confirm the restart by clicking **Continue**.
### Delete app
If you no longer need the application, click **Delete app** and click **Continue** to remove it completely.
Deleting the application **completely removes** the following:
* All files
* Settings
* Persistent storage disks
* Connections to other applications or databases.
# Storage
Source: https://docs.sevalla.com/applications/storage
Manage and configure storage for your applications.
Every process in a Sevalla application comes with ephemeral storage. For data that needs to survive restarts and redeploys, you can also add [persistent storage](https://kinsta.com/blog/persistent-storage/) to a web process or background worker to create a stateful application.
## Ephemeral storage
By default, applications use ephemeral storage with a 20 GB limit per instance. This storage is cleared whenever the instance restarts or redeploys, so it should not be used to retain data.
If a workload writes more than 20 GB to ephemeral storage, the instance is terminated and exits with code `137`. This exit code is commonly associated with out-of-memory kills, but it can also indicate that the ephemeral storage limit was reached.
If your application needs more than 20 GB of writable space, use one of the following instead:
* [Persistent storage](#add-persistent-storage) for data that must survive restarts and redeploys, such as user uploads on a single-instance process.
* [Object storage](/object-storage/overview) for larger volumes of files, media, or backups, especially when the application is horizontally scaled.
## Persistent storage
Persistent storage adds a storage volume that retains data even if the application is restarted or redeployed. When you deploy an application at Sevalla with persistent storage, your application’s [pod](/applications/reference/glossary/#pod) is connected to the persistent storage volume. If you redeploy the application, the application pod is rebuilt, but the storage volume remains untouched and is reconnected to the application pod once the deployment is complete.
When deploying or redeploying an application configured with persistent storage on an instance utilizing 8 CPU cores, there may be some downtime, or the application may not work correctly. This is resolved when the deployment is complete and persistent storage is reconnected.
With persistent storage, processes are limited to one instance. You cannot add persistent storage to a cron job or job. There is no [horizontal scaling](/applications/scalability) for processes with persistent storage, but you can vertically scale them by increasing the pod size for the process.
Because persistent storage blocks horizontal scaling, we recommend using [object storage](/object-storage/overview) instead whenever possible. Object storage lets your application scale horizontally across multiple instances while still providing durable storage for files, media, and backups.
## Add persistent storage
You can add persistent storage to your web process or a background worker after you've created the application, within **Applications** > ***app name*** > **Disks**, click **Create disk**.
Complete the fields as follows:
* **Process:** Select the web process or a background worker to add the persistent storage to.
* **Path:** Specify the location of the files to be added to persistent storage (e.g.`/var/lib/data`). If you use Buildpacks, Nixpacks, or Railpack to set up your container image, you must prefix the location of the files with `/app`. For example, if your files are stored in `wp-content/uploads`, the mount path should be `/app/wp-content/uploads`. **Note:** This cannot be the root directory or the directory of any configuration files; a [full list of invalid mount paths](#invalid-mount-paths) is shown below.
* **Size:** Choose the disk size for your persistent storage volume. You can increase the disk size at any time (on the application's **Disks** page), but you **cannot downgrade the disk size** once it has been created.
Click **Create disk**. The persistent storage costs are added to your monthly invoice and are prorated for the first month. For example, if you add a 10 GB persistent storage disk on the 20th of January, you'll be charged for 11 days in January: $3 / 31 \* 11 = $1.06.
### Invalid mount paths
The following mount paths are invalid because mounting data in these paths may cause issues in an application:
* '
* '/app'
* '/etc/'
* '/layers'
* '/lib/'
* '/mnt/'
* '/root/'
* '/usr/local/'
* '/var/'
* '/workspace'
**Note:** You can start a mount path with the paths above; for example, `/app/wp-content/uploads` is a valid path.
## Update persistent storage
To view disk usage and update persistent storage settings, go to **Applications** > ***app name*** > **Disks**. If your disk usage is below 1 MB, the usage will be shown as 0.
To change the mount path or increase the disk size, on the disk you want to change, click the ellipsis and **Update disk**.
You can increase the disk size, but you **cannot downgrade** it. If you need less disk space for persistent storage, you'll need to create a new application with the desired disk size.
If a deployment is in progress, the application is stopped, or if there are any errors, editing the disk space settings is disabled. Once the deployment completes, the application is restarted, or any errors are resolved; you can edit the disk and make changes.
## Delete persistent storage
To delete persistent storage, go to **Applications** > ***app name*** > **Disks**. On the disk you want to remove, click the ellipsis and **Delete disk.** To confirm the deletion, click **Continue**.
## Accessing persistent storage
To access and view files in persistent storage outside of your application, you can use the [Application Web Terminal](/applications/web-terminal/).
You can also use the Application Web Terminal if you need to add files directly to the persistent storage disk outside of your application. For example, when moving from third-party storage or manually adding files that aren't included in your application's repo.
Currently, you cannot push data to the container. Instead, you'll need to initiate a transfer from the container to pull the files to the disk with something like `wget`. First, ensure the method you want to use is available in the storage container. For example, to see a help message with options for `wget`:
```text theme={null}
wget -h
```
With `wget`, you can pull the files to the persistent storage disk with something like the following:
```text theme={null}
wget -O filename.tgz https://user:password@hostname/filename.tgz
```
Note: `user:password@` is needed if the file is protected with basic HTTP authentication (htpasswd). Replace `user` and `password` with the actual user and password used for authentication.
This can also be run in a script, but the authentication details should be stored in [environment variables](/applications/environment-variables/) rather than hard-coded in the script file.
## Backups
We provide daily backups for persistent storage that are stored for 7 days and can be restored by request. When a backup is restored, all data in persistent storage will be rolled back to the time the backup was created.
To request a backup restoration, [open a new chat with our Support team](/support/contact-support/) and ask for your persistent storage to be restored. Be sure to include your application's name and persistent storage mount path in your request.
Only users with access to create an application can request a persistent storage backup to be restored. This means that you need to be the [owner or company administrator](/company-settings/user-management/) in order to request a backup restoration.
If you delete your application, all persistent storage backups are also deleted and cannot be recovered.
## Available disk sizes and pricing
Persistent storage is available for an additional monthly fee, computed at \$0.363/GB per month. You can choose from the following disk sizes:
| **Size** | **Price** |
| -------- | ----------- |
| 10 GB | \$3/month |
| 20 GB | \$6/month |
| 50 GB | \$15/month |
| 100 GB | \$30/month |
| 150 GB | \$45/month |
| 200 GB | \$60/month |
| 300 GB | \$90/month |
| 400 GB | \$120/month |
| 500 GB | \$150/month |
| 750 GB | \$225/month |
| 1 TB | \$300/month |
# Application Failure
Source: https://docs.sevalla.com/applications/troubleshooting/application-failure
Troubleshoot and resolve issues where your application is unresponsive.
In some cases, your application build may succeed, but the application can still fail or time out at runtime.
When this happens, Sevalla will display an error on the Application **Overview** page. To find out more information about the issue, click the application health icon.
The application health shows you information about when the issue occurred, the error code, and the status of the other processes within the application.
If you are still unsure about what is causing the issue, you should also check the following:
## Resources
If your application process reaches its memory or CPU limit, it can trigger a restart loop, causing the application to stop responding.
To check this, within your application, click **Analytics**, select **Show limit,** and review the **Memory usage** and **CPU usage** charts to see if they have reached the limit.
If you have reached the limit, you need to increase the resources for your application. To do this, go to **Processes**, click the ellipsis (three dots) on your web process, and then click **Update process**. Select the resource you require for the application and click **Update process**.
Redeploy the application after updating the resources.
## Runtime logs
If your application enters a restart loop due to a runtime error, the **Runtime logs** will show the cause.
To check these within your application, click **Deployments**, select the individual deployment, and click **Runtime logs**.
Identify and fix the error indicated in the logs, then redeploy the application.
# Connection errors
Source: https://docs.sevalla.com/applications/troubleshooting/connection-errors
Troubleshoot and resolve application connection errors.
This article explains how to resolve timeout and connection errors that may appear after you deploy your application.
## Connection timeout errors
The connection timeout limit between Cloudflare and Sevalla is **185 seconds**. If a process or database query takes longer than 185 seconds, you may see one of the following errors:
> 504 Gateway Timeout
> Error 524: a timeout occurred
You can use an application performance management/monitoring tool like [New Relic](https://newrelic.com/) to pinpoint which process or query is causing the timeout error. If optimizing the process or query to complete in less than 185 seconds isn’t possible, your application or database may need more resources.
To [scale your application’s resources](/applications/scalability) vertically or horizontally, change a pod’s size or increase the number of pods used for the process.
If the issue is with a database query, you can increase the database’s CPU, RAM, and disk space on the [Database Settings page](/databases/settings).
## Upstream connect error
After deploying an application, if there is an issue with the port your application exposes, you may see the following error:
> upstream connect error or disconnect/reset before headers. reset reason: connection failure, transport failure reason: delayed connect error: 111
This error is due to one of the following:
* The application is listening on the wrong port.
* The application isn’t listening to any port.
To resolve this error, update your port within [**Networking**](/applications/networking) > **Update port**.
# Failed deployment
Source: https://docs.sevalla.com/applications/troubleshooting/failed-deployment
Fix and analyze failed deployments with these troubleshooting steps.
When you deploy your application, you may experience an error during the build or rollout phase that causes the deployment to fail. You should always check the individual [Deployment logs and Runtime logs](/applications/deployments#individual-deployment-details), as they may indicate the reason for the failed deployment. This article explains how to troubleshoot specific deployment errors; if your issue still occurs after following these steps, refer to our [general troubleshooting steps](/applications/troubleshooting/general).
## Build process failed – No Buildpack groups passed detection
When deploying an application using [Buildpacks](/applications/build-options/buildpacks), if there is an issue detecting your application's buildpack during the build process, you may see the following error in the [**Deployment logs**](/applications/deployments).
> Build process failed Unknown build fail type
Open the **Deployment logs** and look for errors similar to the following:
> \===> DETECTING ERROR: No buildpack groups passed detection. ERROR: Please check that you are running against the correct path. ERROR: failed to detect: no buildpacks participating ERROR: failed to build: executing lifecycle: failed with status code: 20
These errors occur when there isn't enough information to correctly detect the type of application. This is usually caused by one of the following:
* The Git repository doesn't contain all the files needed for the application.
* Something within the code or settings causes an incorrect buildpack to be selected.
* The build path is incorrect.
### Git repository
Check your repository to ensure all the correct files have been pushed into the repository for your application.
### Buildpack
Sevalla uses [**Nixpacks**](https://docs.sevalla.com/applications/build-options/nixpacks) by default to build your application and set up the container image. You can choose to use [Railpack](/applications/build-options/railpack) or [Buildpacks](/applications/build-options/buildpacks) within **Settings** > **Build strategy** > **Update build strategy**. If your application requires additional buildpacks, you can also add them here.
When using buildpacks, you must also ensure the correct language version is in your application's files. For more details, see our documentation on specifying a language version for [Buildpacks](/applications/build-options/buildpacks).
### Build path
The build path is where the files to build your application are located in the repository. Usually, this is the repository root, and you do not have to set a build path when adding your application.
If your application has a different build path, you can change it in [**Settings**](/applications/settings/) (**Settings** > **Build strategy** > **Update build strategy**). For example, if your application needs to be built from a subdirectory named **app**, enter that subdirectory path as **/app** in the **Build path** field.
## Failed build due to Buildpack version
When deploying an application using [Buildpacks](/applications/build-options/buildpacks), you may receive an error regarding the Buildpack version, such as:
> Please switch to one of our newer 'heroku/builder:\*' builder images, such as 'heroku/builder:22'
This may be due to an updated build configuration in Sevalla. To resolve this:
1. In [Sevalla](https://app.sevalla.com/), click **Applications** > ***app name*** > **Processes** > edit the **Web process** > for Laravel applications, enter the following start command: `heroku-php-apache2 /public` for all other PHP applications, remove the **Start command**.
2. Click **Update process**.
3. Click **Deployments** > **Deploy now**.
## Failed rollout
When deploying an application, if there is an issue with deployment, you may see one of the following errors:
> Build process failed Unknown build fail type
If the rollout process fails immediately, or if the build process fails, no pods are created, and runtime logs do not exist, an incorrect start command in the web process is most often the cause (or an incorrect `ENTRYPOINT` in the Dockerfile if your application is built from a Dockerfile).
If the rollout process runs for a minute or two and then fails, this usually means the pods were created, but something went wrong, and the process stopped. In this case, you should check the [deployment runtime logs](/applications/deployments#runtime-logs) to identify any error messages. The error messages can help you identify bugs in the application's code so you can debug the issue.
If you cannot identify the issue, check the following, and if the issue persists, [contact our Support team](/support/contact-support/).
### Git repository
Check your repository to ensure all the correct files have been pushed into the repository for your application.
### Language
When you add your application and choose to use [Nixpacks](/applications/build-options/nixpacks) or [Buildpacks](/applications/build-options/buildpacks) to create your application's container image, we automatically determine and set up a container for your application. When using Nixpacks or Buildpacks, if you do not want the default or latest available version of the language to be used, you must set the language version in your application's files. For more details, see our documentation on [specifying a language version for Buildpacks](/applications/build-options/buildpacks#set-a-buildpacks-language-version) or [specifying a language version for Nixpacks](/applications/build-options/nixpacks#set-a-nixpacks-language-version).
Additionally, if you deploy a PHP or Python application with Nixpacks and the rollout fails when the container image is built, this is most likely due to a missing language version in the application's code, particularly if the deployment works with Buildpacks but not with Nixpacks. Check the following to make sure the language version is set:
#### PHP
If there is a **composer.json** file in your repository, it must contain the `require` key with the PHP version, like the following:
```text theme={null}
{
"require": {
"php": "~8.1.0"
}
}
```
#### Python
To specify your Python version, include the following in your application's **runtime.txt** file:
```text theme={null}
python-3.10.13
```
### Start command or ENTRYPOINT
The **Start command** for the [web process](/applications/processes) starts your application. If this is incorrect, the application will not run. You can check the command in **Processes** > **Web process**.
If your application uses a [Dockerfile](/applications/build-options/dockerfile) to set up your container image, you must specify the `ENTRYPOINT` in the Dockerfile to run a container. For more information about how to specify your application's `ENTRYPOINT`, see the [Dockerfile reference](https://docs.docker.com/reference/dockerfile/#entrypoint).
### Build path or Dockerfile context
You can choose [Nixpacks](/applications/build-options/nixpacks), [Railpack](/applications/build-options/railpack), [Buildpacks](/applications/build-options/buildpacks), or a [Dockerfile](/applications/build-options/dockerfile) for your container image. You can update the Build path or Dockerfile context within **Settings** > **Build strategy** > **Update build strategy**
* **Build path:** This only applies to Nixpacks, Railpack, and Buildpacks. This is the path in the repository to the files required to build the application. Most applications are built from the repository root, and the **Build path** defaults to this (.). If you have a different build path, specify it here. For example, if your application needs to be built from a subdirectory (e.g., **app**), enter that subdirectory path in the **Build path** field: **app**. This is also useful if you have a [monorepo](https://kinsta.com/blog/monorepo-vs-multi-repo/).
* **Context:** This only applies to Dockerfiles. This is the path in the repository we need access to so we can build your application. Most applications are built from the repository root, and you can enter the repository root (**.**) in the **Context** field. If your application needs to be built from a subdirectory (e.g., **app**), enter that subdirectory path in the **Context** field: **app**.
You can view and change the **Build path** or **Dockerfile Context** in **Settings** > **Build** > **Update build strategy**.
### Environment variables
[Environment variables](/applications/environment-variables) feed your application information from outside of the running of that application. An incorrect environment variable may prevent your application from running. You can check your environment variables in **Environment variables**.
Confirm that the correct environment variables exist and contain valid values. There are a few important things to keep in mind when creating and checking environment variables:
* Each key must be unique, and a key can only be added once.
* [Parentheses](/applications/environment-variables#parentheses) can cause the build or rollout process to fail, depending on when they are available during deployment. They **cannot** be used in environment variables.
* [Unescaped commas](/applications/environment-variables#commas) are interpreted as delimiters by the rollout process, so they **cannot** be used in environment variables. If you need to use a comma in your environment variable value, you must escape it with a backslash (`\`).
* [Unescaped double quotes](/applications/environment-variables#double-quotes) are either disregarded or will cause the rollout process to fail. If you need to use double quotes in your environment variable value, you must escape them with a backslash (`\`).
### Port
Only ports 80 and 443 are open for application hosting. You can change the port your application's web process uses when you add the application or within **Networking** > **Update port**.
### Invalid package name
An invalid package name in **package.json** can cause an error. For example, do not use "js" or "node" in the name. For more details, see the [specifics of npm's package.json handling](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) in the npm Docs.
## Deployment timing out
If the build succeeds but the deployment times out, it may be due to insufficient runtime resources on one of the [application processes](/applications/processes). To resolve this, increase the allocated resources by selecting a pod size with more CPU or RAM for the process. You can adjust this within **Processes**. On the process, click the kebab (three dots), select **Update process**, and change the **Resource** size.
## Error: failed to solve: process
When deploying a Laravel application, you may get the following error:
> ERROR: failed to solve: process "/bin/bash -ol pipefail -c npm run build" did not complete successfully: exit code: 126
This error is caused when the `vendor` and `node_modules` folders are present within the repository. These folders are generated during the build process and should, therefore, be removed from the repository to resolve this issue.
# General troubleshooting
Source: https://docs.sevalla.com/applications/troubleshooting/general
General troubleshooting for common issues in your applications.
If you have an issue with your application, consider and try to rule out the following:
* Database connectivity issues.
* Environment variables:
* Incorrect variables.
* [Special characters](/applications/environment-variables#special-characters-in-environment-variables).
* [Base64 Encoded Variables](/applications/environment-variables#base64-encoded-variables).
* Connectivity issues with external applications.
* Bad **Start commands**. For example, if you are trying to use `yarn` when only `npm` is available, or a **package.json** file without the required start script.
* When chaining **Start commands**, the last command **must initiate a web service**. This keeps the container running and listening to incoming connections.
* An invalid package name in **package.json**. For example, do not use “js” or “node” in the name. For more details, see the [specifics of npm’s package.json handling](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) in the npm Docs.
* Permission issues.
* Missing files.
## General troubleshooting steps
1. Change the start command to `sleep 9999`. This will get the pod into a running state where you can interact with it via the [Web terminal](/applications/web-terminal). Edit the [web process](/applications/processes#web-process) to change the start command (**Processes** > **Web process** > **Update process**).
2. Open the Web terminal.
3. Check the [environment variables](/applications/environment-variables). In the web terminal, enter `printenv` and check that the environment variables are what you expect them to be.
4. Run the application manually. Try running the application manually with debug options enabled. The command to do this may vary, depending on the application. For more details, check the documentation for the language or package manager your application is built with.
5. Try to build the application locally:
* For Buildpacks, you can use the `pack build` command to build your container images locally. For example:
```
pack build --path --buildpack heroku/ -v
```
* For Nixpacks, you need to [install Nixpacks](https://nixpacks.com/docs/install) locally and run `nixpacks build` within your application directory.
* For Railpack, you need to [install Railpack](https://railpack.com/installation) locally and run `railpack build` within your application directory.
# HTTP status codes
Source: https://docs.sevalla.com/applications/troubleshooting/http-status-codes
Understand and fix HTTP status code errors in your app.
After deploying your application, when you go to the application’s URL, you may receive an HTTP status code identifying an issue with the server or client. This article explains how to resolve these status codes.
## 403 error
After deploying your application, if there’s an issue with file permissions or the workspace path, you may see the following or a similar error when you try to go to your application’s URL:
> 403 Forbidden
> You don’t have permission to access this resource.
This error is usually caused by one of the following:
* Incorrect file permissions.
* Incorrect configuration within an .htaccess file.
* Configuration error in the workspace path in Apache configuration.
If you cannot identify the issue, check the following, and if the issue persists, [contact our Support team](/support/contact-support/).
### File permissions
File permissions control who can:
* **Read:** See the contents of a file or view files in a directory.
* **Write:** Modify a file, or add or delete files in a directory.
* **Execute:** Run a file and/or execute it as a script, or access a directory and perform functions and commands.
Each file and directory has its own set of file permissions, shown as a 3-digit number. Each number indicates the permission level for each category (read, write, and execute) shown above. We generally recommend the following permissions, but there could be cases where these need to be different for your application (e.g. some applications may need permissions on files to be set to 755 or 750):
* **Files:** 644 or 640
* **Directories:** 755 or 750
Make sure file permissions are set for your application. We recommend checking the documentation for your application, language, or framework if you are unsure.
### .htaccess file
If your application’s code includes an .htaccess file, verify that any configuration directives in it are correct. For example, a misconfigured `Rewrite` or `FilesMatch` directive can cause a 403 error.
### Workspace path
If your [application uses a buildpack](/applications/build-options/buildpacks) and an Apache web server, an incorrect workspace path in your Apache configuration can cause a 403 error. The [application logs](/applications/runtime-logs) may show an error similar to the following:
```
python: can't open file '/workspace/server.py': [Errno 2] No such file or directory
```
This error shows that the command the buildpack is trying to run doesn’t exist. Update your Apache configuration to use **/workspace/web/** (instead of **/workspace/** or similar) to resolve this issue.
## 503 error
After a successful application deployment, if there’s an issue within the application’s code or configuration, you may see the following error when you try to go to your application’s URL:
> 503 Service Temporarily Unavailable
If you cannot identify the issue, check the following.
### Workspace path
If your [application uses a buildpack](/applications/build-options/buildpacks) and an Apache web server, an incorrect workspace path in your Apache configuration can cause a 503 error. The [application logs](/applications/runtime-logs) may show an error similar to the following:
```
python: can't open file '/workspace/server.py': [Errno 2] No such file or directory
```
This error shows that the command the buildpack is trying to run doesn’t exist. Update your Apache configuration to use **/workspace/web/** (instead of **/workspace/** or similar) to resolve this issue.
**Note:** This issue may also present as an `oom-killed` error in the runtime logs (but it isn’t the only possible cause of an `oom-killed` error).
If the error persists after checking and fixing any configuration issues, follow our [Failed Deployment troubleshooting](/applications/troubleshooting/failed-deployment/) guide. If the error remains beyond those steps, [contact our Support team](/support/contact-support/).
# Missing repository
Source: https://docs.sevalla.com/applications/troubleshooting/missing-repository
Solutions for missing repository problems in your deployments.
When working with an application, you may see an error similar to the following:
> Missing repository
>
> It seems like this repository is not available anymore **Edit… permissions**
The following are a few things you can check to resolve the error.
## Expired token or revoked access
When you connect your Git provider ([GitHub](/applications/git/github), [Bitbucket](/applications/git/bitbucket), or [GitLab](/applications/git/gitlab)), you generate a user access token with an expiration date.
When the token expires or if you revoke access, it can no longer access your repository or your account at your Git service provider. To resolve this, click the link in the error message to generate a new user access token so you can reconnect your Git provider to Sevalla.
## Sevalla integration update
If we release an update to the Git integration application, you may need to create a new user access token. To resolve this, click the link in the error message to generate a new user access token so you can reconnect your Git provider to Sevalla.
## Deleted repository
If the repository has been removed from your Git provider, Sevalla can no longer access the application. If you or your development team did not delete the repository, you’ll need to check with your Git provider to investigate why the repository has been removed.
# PHP errors
Source: https://docs.sevalla.com/applications/troubleshooting/php-errors
Troubleshoot PHP errors in your application deployments.
When your application is running, you may notice PHP errors within your application logs, or you may want to ensure your PHP scripts are not running indefinitely due to incomplete or stalled requests. This article explains how to configure appropriate timeout settings and memory limits to ensure the stability, security, and optimal performance of your application.
## Memory limit
The default PHP memory limit on Application Hosting is **128MB** for all PHP versions. If your application exceeds this limit, you may see an error similar to the following in your [application logs](/applications/runtime-logs):
> Detected 1047468200 Bytes of RAM
> PHP memory\_limit is 128M Bytes
The memory limit is restricted by the pod size you use for your application processes. If you set this too high, it may consume excessive system resources, so it’s important to thoroughly test your application if you change the memory limit.
To increase your application’s memory limit, create a **.user.ini** file in the application’s root directory and add the memory limit setting to the file. For example, if you want to increase the PHP memory limit to 256MB, add the following:
```text theme={null}
memory_limit = 256M
```
## Increase request terminate timeout
The `request_terminate_timeout` directive for FastCGI Process Manager (FPM) determines the maximum time a PHP script can run before the web server forcefully terminates it, regardless of whether the script has completed or not.
This is useful for preventing PHP scripts from running indefinitely, which can happen due to coding errors, infinite loops, or excessive processing times. By setting an appropriate `request_terminate_timeout`, you can prevent PHP processes from consuming excessive server resources and potentially affecting the overall performance and stability of the server.
To change the value of request\_terminate\_timeout:
1. Create a file named **fpm\_custom.conf** within the root directory of your repository and add the required value within it, for example (default unit is seconds):
2. `request_terminate_timeout = 120`
3. Push the changes to your Git repository.
4. Within Sevalla, select your application > **Processes** > edit the **Web process** > update the **start command** to include the fpm\_custom.conf file, for example: `heroku-php-apache2 -F fpm_custom.conf`
## Increase max execution time
`max_execution_time` defines the maximum amount of time, in seconds, that a PHP script is allowed to run before it is terminated by the server.
To increase your application’s max execution time, create a **.user.ini** file in the application’s root directory and add the max execution time setting to the file. For example, if you want to increase the max execution time to 60 seconds, add the following:
```text theme={null}
max_execution_time = 60
```
**Note:** Cloudflare's 185-second limit restricts this value to a maximum of 185 seconds and cannot be changed.
When you change the `max_execution_time` you should also update the `request_terminate_timeout` value to ensure the script is not terminated before the execution time.
# Skip pruning
Source: https://docs.sevalla.com/applications/troubleshooting/skip-pruning
Guidance for using skip pruning in deployment workflows.
When deploying a Node.js application, if the `NODE_ENV`[environment variable](/applications/environment-variables) hasn’t been set to production, you may see the following warning:
> Skip Pruning Because NODE\_ENV is Not ‘Production’
This occurs because the `NODE_ENV` variable isn’t set to production by default during application creation.
To resolve or prevent this issue, manually add the `NODE_ENV` in your [**application’s Environment variables**](/applications/environment-variables).
# Web terminal
Source: https://docs.sevalla.com/applications/web-terminal
Access your application containers directly using the integrated web terminal.
The application **Web terminal** gives you command-line access to the container your application's web process, background worker, or cron job is running in. You can use the web terminal to **run scripts** and **read files**. This is useful for debugging issues, performance monitoring, or manually executing scripts ad hoc.
To access the web terminal, you'll need to:
* Have at least one successful [deployment](/applications/deployments/) of the application.
* Have a healthy application that is running. If there are any errors or the application is stopped, the web terminal will not be available.
Logs are not available in the web terminal. Any files you create in the terminal will not be available to your application unless you have added persistent storage and the files are being created in the persistent storage volume. Any file changes made in the terminal will be lost with the next application deployment unless you have added persistent storage and you're changing files stored in the persistent storage volume.
## Web terminal
You can access the **Web Terminal** from **Applications** > ***app name*** > **Web terminal**. You can switch the shell type from the first dropdown menu and choose between `sh`, `bash`, and `zsh`. You can also switch between your web process, background worker, or cron job.
## Nixpacks binary directories
With Nixpacks, the binary directories may differ from the default binary directories for the application language. The following table shows the binary directories used for some of the most common languages:
| Language | Directory |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Node.js | **/nix/var/nix/profiles/default/bin/node** |
| Ruby | **/nix/var/nix/profiles/default/bin/ruby** |
| Python | **/nix/var/nix/profiles/default/bin/python** |
| Java | **/nix/var/nix/profiles/default/bin/java** |
| Scala | Scala doesn't have a specific default binary path like some other compiled languages. When you compile a Scala program, it generates bytecode that runs on the Java Virtual Machine (JVM). The compiled Scala classes are typically stored in a directory structure that mirrors the package structure of your code. This is similar to how Java classes are organized. By default, when you compile a Scala source file, the compiled .class files will be placed in the same directory as the source code (within a subdirectory structure based on the package declarations).
If needed, you can install Scala's runtime tools using a Dockerfile instead of using a Nixpack.
|
| PHP | **/nix/var/nix/profiles/default/bin/php** |
| Go | Go doesn't have a specific default binary path like some other compiled languages. When you compile a Go program, the resulting binary executable is typically placed in the same directory as your source code by default. If needed, you can install Go's runtime tools using a Dockerfile instead of using a Nixpack.
|
## Buildpack binary directories
When you add an application in Sevalla using Buildpacks, the binary directories may differ from the default binary directories for the application language. The following table shows the binary directories used for each buildpack language:
| Language | Directory |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Node.js | **/layers/heroku\_nodejs-engine/dist/bin/node** |
| Ruby | **/usr/bin/ruby** |
| Python | **/usr/bin/python** |
| Java | **/layers/heroku\_jvm/openjdk/bin/java** |
| Scala | Scala doesn't have a specific default binary path like some other compiled languages. When you compile a Scala program, it generates bytecode that runs on the Java Virtual Machine (JVM). The compiled Scala classes are typically stored in a directory structure that mirrors the package structure of your code. This is similar to how Java classes are organized. By default, when you compile a Scala source file, the compiled .class files will be placed in the same directory as the source code (within a subdirectory structure based on the package declarations).
If needed, you can install Scala's runtime tools using a Dockerfile instead of a buildpack.
|
| PHP | **/workspace/.heroku/php/bin/php** |
| Go | Go doesn't have a specific default binary path like some other compiled languages. When you compile a Go program, the resulting binary executable is typically placed in the same directory as your source code by default. If needed, you can install Go's runtime tools using a Dockerfile instead of a buildpack.
|
## Django/Python commands with Nixpacks
If you're using Nixpacks and want to run Django/Python commands within the web terminal, you must first activate the virtual environment with the following command:
```
. /opt/venv/bin/activate
```
Then run the following command:
```
python manage.py
```
## Troubleshooting
* When opening the web terminal, if you see an **Error 1016 – Origin DNS** page instead of the terminal screen, this is due to a slight delay in DNS propagation. Wait 1 minute and refresh the page until you see the terminal screen. If the issue persists beyond a few minutes, [contact our Support team](/support/contact-support/).
* When you open the web terminal, if you see the error **Connection closed with error code: 4005** or **4001**, check that your application is running and you can access the application.
# Application pricing
Source: https://docs.sevalla.com/billing/application-pricing
See detailed pricing for application hosting and related services.
[Application Hosting](https://sevalla.com/application-hosting/) pricing is usage-based. This means that you only pay for the [resources your application uses](/applications/analytics/). You can estimate your monthly costs with the [Sevalla pricing calculator](https://sevalla.com/pricing/calculator/) before you deploy. Billing cycles run from the 1st day of the month to the 1st day of the following month, and we charge your default payment method on the 1st of each month for the previous cycle's usage.
The application billing amounts are included in the **Spending overview** chart on your Sevalla Dashboard. This chart shows the spending overview for all Sevalla services.
For detailed information about your application costs, the **Usage** page within **Company settings** provides complete visibility into your resource consumption and costs for both the current and previous billing periods across all your services.
Your invoice will be based on the following:
* Bandwidth (egress only)
* Build time
* Application hosting pod usage
## Bandwidth
If your application has a web process that allows users to access it via the Internet, the traffic flowing out of the application to the user (egress) is the bandwidth we charge for. We do not charge for traffic coming into your application (ingress).
This bandwidth is calculated and billed on a per-byte basis at a price of $0.0000000001 per byte ($0.1 per GB). This means no rounding or charges based on every “started” Gigabyte. You will only be charged for **actual** usage. You can see your usage on the [Bandwidth](/applications/analytics/#bandwidth) chart in **Analytics**.
## Build time
Applications or sites need to be built in secure, isolated environments and require resources such as RAM, CPU, and disk to be available. The build time is charged at $0.0003333 / second or $0.02 / minute. You can see how long each build has taken on the [Build time](/applications/analytics/#build-time) chart in **Analytics**.
If you change your application during the build process and need to build it again, you can [**cancel the build within Deployments**](/applications/deployments) to save any unnecessary build costs.
## Application Hosting pods
An application can have multiple processes. Each process has its own dedicated resources, and you can select a pod for each individually. You will be billed for each pod according to its size and how long it is used (in seconds). You can see the [Runtime](/applications/analytics/#runtime) for each application process in **Analytics**.
As an example, you could have the following application setup:
* A web process for an online store that requires a lot of power, using a C3 Pod (4 CPU / 4 GB RAM) for \$135 per month.
* A background process that creates statistics based on orders and needs a lot of power, using an M3 Pod (2 CPU / 8 GB RAM) for \$135 per month.
* Another background process runs once a day and requires very little processing power, using an S2 Pod Type (1 CPU / 2 GB RAM) for \$40 per month.
For the month of March, the web process runs for the full month, and the background jobs only run for 30 minutes a day. So the total usage (there are 744 hours or 2,678,400 seconds in March) is:
* 2,678,400 seconds of usage for the web process
* 55,800 seconds of usage for the first background process
* 55,800 seconds of usage for the other background process
Multiply the usage by the cost for each pod to calculate the total amount to be billed.
* 2,678,400 \* $0.0000513698630 (price per second) = $137.59
* 55,800 \* $0.0000513698630 (price per second) = $2.87
* 55,800 \* $0.0000152207002 (price per second) = $0.85
Total = \$141.31
**Note:** If you choose a **Hobby** pod size for your web process, you will **not** be able to [add a custom domain to your application](/applications/domains). If you need a custom domain for your application, you can upgrade this anytime.
## Summary
With our direct usage-based approach to Application Hosting pricing, if you create an application and delete it after a day, you only pay for the time used on that day. For insights into your application’s usage data, see [Application Analytics](/applications/analytics/).
# Billing
Source: https://docs.sevalla.com/billing/billing
Review and manage your billing information.
Within billing, you can add and update your payment methods, update your billing address and [VAT number](/billing/tax-vat-gst), and view and download your invoices and receipts.
With our multi-user feature, you can create and manage a team and give them access to various aspects of your account, such as billing. For a detailed explanation of the different access types, refer to [User Management](https://docs.sevalla.com/company-settings/user-management).
To grant access to billing, you can invite a company billing user who only sees billing details and company settings. They can see invoices and modify company details like name, address, and payment method. They do not have access to any websites in any way. To give a user company billing access, select **Company billing** when you [invite the user to your company](/company-settings/user-management/#invite-a-user).
## Payment methods
In order to process payments, we ask you to input your payment details in Stripe, our credit card processing company. Stripe is one of the [most secure](https://docs.stripe.com/security) payment providers in the industry.
### Add your credit/debit card in Sevalla
A valid payment method is required to use Sevalla's services. After signing up, you must add your billing details and a payment method before you can create or manage any resources in Sevalla.
To add your credit or debit card, click **Company settings** > **Billing** > **Manage billing**.
This opens the Stripe platform, click **Add payment method**.
You can then choose your payment method and enter your payment details. A couple of important notes regarding the CVC number:
* Your CVC number is a three-digit number found on the back of your card.
* If you have an American Express card, the CVC is a four-digit number on the front of your card.
Once you’ve entered your card details, select the check box if you would like this to be the default payment method, and then click **Add**.
You can add multiple cards, but our payment system only charges the card marked as default. Additional cards on file are not used as a fallback if the default card fails.
You can change your default card at any time from **Manage billing** by clicking the kebab (three-dot) menu for that card and choosing **Make default**. You can also delete any unneeded non-default card at any time.
You can't remove the default payment method directly. To remove it, first mark another card as default, then delete the previous card.
Keeping your payment information up to date helps to prevent service interruptions caused by [failed payments](/billing/failed-payments).
To change the card holder name, credit or debit card number, CVC number, or expiration date, you’ll need to add a new card.
## Billing details
Only the [Company Owner](/company-settings/user-management/#company-owner), [Company Administrator](/company-settings/user-management/#company-administrator), and [Company Billing](/company-settings/user-management/#company-billing) roles can update the billing details.
The billing details show if you're an individual or an organization, your billing address, and your [VAT number](/billing/tax-vat-gst), if applicable.
To update your billing address in Sevalla, click **Company settings** > **Billing** > **Manage billing**.
This opens the Stripe platform, click **Update information**.
Update the required details and click **Save**.
## Invoices
From April 23, 2026, all invoices are stored within [Stripe.](http://Stripe.To) To access them, click **Manage Billing**, and they are shown in the **Invoice History** section.
### Historical invoices
Invoices that were generated before April 23, 2026, are shown in **Company settings** > **Billing** > **Historical invoices**.
## Danger zone
If you are the [Company Owner](/company-settings/user-management/#company-owner), the bottom of the Billing page shows a **Danger zone** with the **Delete company** option. Deleting your company cancels your Sevalla subscription, settles your final balance immediately, and permanently deletes the company. For the full walkthrough and eligibility requirements, refer to [Delete company](/company-settings/delete-company).
# Database pricing
Source: https://docs.sevalla.com/billing/database-pricing
See detailed pricing details for database hosting plans.
[Database Hosting](https://sevalla.com/database-hosting/) pricing is usage-based. You can estimate your monthly costs with the [Sevalla pricing calculator](https://sevalla.com/pricing/calculator/) before you deploy. Billing cycles run from the 1st day of the month to the 1st day of the following month, and we charge your default payment method on the 1st of each month for the previous cycle's usage.
The database billing amounts are included in the **Spending overview** chart on your Sevalla Dashboard. This chart shows the spending overview for all Sevalla services.
For detailed information about your database costs, the **Usage** page within **Company settings** provides complete visibility into your resource consumption and costs for both the current and previous billing periods across all your services.
Your invoice will be based on:
* The [database size](/databases/get-started/add-a-database) (database resource type) and [runtime](/databases/analytics#runtime)
* Egress bandwidth, if applicable
## Database size and runtime
Each database size contains a set amount of CPU, RAM, and disk space available. Database runtime is calculated based on seconds of usage.
If you require more disk space but don’t want to increase the RAM or CPU, you can purchase a database disk space add-on for \$10 per 10 GB.
Due to the size of the databases in Database Hosting plans 7-9, to ensure the stability and speed of the database application, the amount of usable RAM and CPU may be 4.4% – 9.4% less than indicated. These resources remain dedicated to the underlying system that runs your database.
### Database disk space add-on
The database disk space add-on allows you to increase your database disk space without increasing the RAM or CPU. You can purchase the database disk space add-on in 10 GB increments at \$10/month per database and purchase as many of these add-ons as you want.
This add-on is billed monthly and is prorated for the first month. For example, if you add 4 of the database disk space add-ons (a total of 40 GB) on the 20th of January, you’ll be charged for 11 days in January: ($10 \*4) / 31 \* 11 = $14.19.
### Add the database disk space add-on
If you would like to add the database disk space add-on to your database, follow the steps below.
If you do not have a database, you’ll need to create one before requesting the disk space add-on. Make sure the database has the appropriate RAM and CPU for your database.
1. [Open a new chat](/support/contact-support/) with our Support team and request that the database disk space add-on be added to your database. Please note that only users with billing permissions (Company owners, Company admins, and Company billing) can request the addition of the add-on.
2. Our Engineering team will increase your database disk space. Our Billing team will add the database disk space add-on subscription to your account. The add-on is \$10 a month per 10GB of space. Please allow 1 business day (weekends are not included in business hours) for the increase in database disk space.
3. Our Support team will notify you once the database size has been increased.
### View the database disk space add-on in Sevalla
The add-on will appear in your upcoming or paid invoices in **Company settings** > **Billing** > **Manage billing**.
The total database disk size, including any disk space add-on, is shown in the Database **Overview**.
The **Storage** chart in [Database Analytics](/databases/analytics#storage) shows the current amount of data storage, including any add-on storage space.
### Modify or remove the database and database disk space add-on
#### Upgrade database
If you upgrade your database resources within **Settings** > **Update details**, this removes the additional disk space for the database, but you will continue to be **billed for the add-on** **subscription**. The upgrade must be the same disk space as the total database disk size, including the add-on or higher. For example, if you have a disk space add-on that increases the total disk space to 60 GB, you must choose a DB 6 plan or higher.
If you want to upgrade your database and no longer need the disk space add-on, you’ll need to contact our Billing team to cancel the subscription.
If you need to upgrade your database resources **and** keep the disk space add-on, you must contact our Support team for any changes to ensure the upgrade is implemented properly and you are invoiced correctly.
#### Downgrade database
You cannot downgrade (decrease) a database's resource type through **Settings** > **Update details**. The **Update details** flow only lets you increase the size. This applies to any database type.
If you need a smaller database, [create a new database](/databases/get-started/add-a-database) with the desired resource type and move your data over. The easiest way is to [restore a backup](/databases/backups#restore-a-backup) to the new database, which works as long as it's the same database type and in the same data center. Once the data has been moved, you can delete the old database. See [Database settings](/databases/settings) for more on changing database resources.
If you have a disk space add-on, deleting the old database does not cancel the add-on subscription. You'll need to contact our Billing team to cancel it.
#### Delete database
If you delete your database, you’ll need to contact our Billing team to cancel the database disk space add-on subscription. Removing the database does not automatically cancel the add-on subscription, and adding a new database does not associate the add-on with the new database.
### Important notes
* The database disk space add-on is only available in 10 GB increments. For example, if you need 15 GB of additional space, you’ll need to purchase 2 add-ons for a total of 20 GB of additional space.
* Upgrading or deleting your database doesn’t change the add-on subscription. You will continue to be billed for the add-on subscription until you contact our Billing team.
## Egress bandwidth
If you use an [external connection with your database](/databases/connections), external bandwidth usage charges may also apply. This egress bandwidth is calculated and billed on a per-byte basis at a price of $0.0000000001 per byte ($0.1 per GB). This means no rounding or charges based on every “started” Gigabyte. You will only be charged for **actual** usage. You can see your usage on the [Bandwidth](/databases/analytics#bandwidth) chart in **Analytics**.
[Internal connections](/databases/connections) between an application and a database are free.
## Summary
With our direct usage-based approach, if you create a database and delete it after a day, you only pay for the time used that day. If you need more disk space for your database, you can increase its size or add more storage space with the database disk space add-on.
# Failed payments
Source: https://docs.sevalla.com/billing/failed-payments
Troubleshoot and resolve failed payment issues on your account.
Sevalla billing cycles run from the **1st day of the month to the 1st day of the following month**. We charge your default payment method on the **1st day of every month** for the previous cycle's usage. If a payment fails, you have until the **15th of the same month** to resolve the issue before your company is suspended.
## Unpaid invoice notice
If you have an unpaid invoice, a red **Past due invoice** notice appears in the [Sevalla](https://app.sevalla.com/) dashboard when you log in. Click the notice to view the overdue invoice and pay it directly. As soon as the invoice is paid, your company is automatically reactivated and all services resume.
## Payment methods
You can [add more than one credit card](/billing/billing/#payment-methods) to your account and set any card as your default. We only charge the card marked as default - additional cards on file are not used as a fallback.
We exclusively use Stripe as our credit card processor; we don't accept PayPal payments.
## Failed payment timeline
Payments may fail due to insufficient funds, expired cards, or banks declining the transaction. The most common cause is a bank declining the charge. If this happens, contact your bank and ask them to allow Sevalla Inc. to process the payment.
The diagram below shows an example timeline for a payment that fails on March 1st and is never resolved:
```mermaid theme={null}
timeline
title Failed payment timeline (example - March billing cycle)
Mar 1 : First charge attempt fails
: First payment failed email sent
Mar 2-13 : 6 reminder emails sent
Mar 14 : Final notice email sent
Mar 15 : Final charge attempt fails
: Company suspended
: Suspension email sent
Jun 13 : 90 days after suspension
: Company and all services permanently deleted
```
At any point before the 90-day deletion deadline, paying the past due invoice automatically reactivates the company.
### Day 1 - First payment attempt
On the 1st of the month, we charge your default card. If the charge fails, we send the **first payment failed email** to the [Company Owner](/company-settings/user-management/#company-owner), all [Company Administrators](/company-settings/user-management/#company-administrator), and all [Company Billing](/company-settings/user-management/#company-billing) users. This email comes from [noreply@sevalla.com](mailto:noreply@sevalla.com), so check your promotions tab and spam folder if you don't see it. All subsequent failed payment emails (reminders, final notice, and suspension) are also sent to the same recipients.
### Days 2-13 - Reminder emails
Between the 2nd and the 13th, we send **six reminder emails** about the unpaid invoice. Each email asks you to update your payment details or work with your bank so the charge can be processed.
You can pay the invoice at any time without waiting for the next retry. Go to **Company settings** > **Billing** > **Manage billing**, and click **Pay** next to the failed invoice.
### Day 14 - Final notice email
On the 14th, we send the **final notice email**. This is your last warning before the company is suspended. You have until the next day to resolve the payment.
### Day 15 - Final charge and suspension
On the 15th, our billing system makes a **final charge attempt** on your default card. If this attempt fails, your company is **immediately suspended** and we send the **suspension email**. While suspended:
* All traffic and processes stop. Visitors cannot reach your sites or applications.
* You cannot deploy or redeploy applications.
* You cannot connect to your databases or retrieve data.
### 90 days after suspension - Permanent deletion
If the suspension is not resolved within **90 days**, your company and **all of its services are permanently deleted**. This includes all applications, databases, static sites, and stored data. Deletion is permanent and cannot be reversed.
## Reactivating a suspended company
To reactivate a suspended company, pay the outstanding invoice from the **Past due invoice** notice in the dashboard, or from **Company settings** > **Billing** > **Manage billing**. Once payment succeeds, the company is automatically reactivated and all services resume.
If you have any issues with your payment, open the [Sevalla](https://app.sevalla.com/) dashboard and contact support via the Intercom chat before the 90-day deletion window closes.
## Important notes
* We suspend all services under a company if any invoice on that company is unpaid, including services that are otherwise current.
* If we suspect fraudulent activity, your account is suspended and you will not be able to access anything within your company on Sevalla.
* After permanent deletion at 90 days, data cannot be recovered.
# Billing - FAQs
Source: https://docs.sevalla.com/billing/faqs
Frequently asked questions related to billing and payments.
Have a billing question about your hosting plan at Sevalla? No problem, we’ve compiled all the most common billing questions and issues clients typically run into, all in one place.
Many of the questions below come directly from our billing and sales teams and are sorted, for the most part, in order of most frequently asked.
## How can I estimate my monthly costs?
Sevalla's [Application Hosting](/billing/application-pricing), [Database Hosting](/billing/database-pricing), and [Static Site Hosting](/billing/static-site-pricing) are usage-based, so you only pay for the resources you use. To estimate your monthly costs before you deploy, use the [Sevalla pricing calculator](https://sevalla.com/pricing/calculator/). Once your services are running, you can track actual spending on the **Spending overview** chart on your Dashboard and the [Usage](/billing/usage) page in **Company settings**.
## I added my VAT number, but my invoice still shows a VAT charge.
If you’ve already added your VAT number, but your upcoming invoice still shows a VAT charge, here are a couple of reasons why:
1. The VAT number is not valid or doesn’t exist.
2. The VAT number format is incorrect.
3. For EU VAT numbers, it should always be a two-letter country code followed by 10 numbers without any extra characters. For example, this is how a Belgian VAT number would appear: `BE0661333385`. You can manually check VAT numbers on the [European Commission’s website](https://ec.europa.eu/taxation_customs/vies/#/vat-validation).
4. For [UK VAT numbers](https://www.tax.service.gov.uk/check-vat-number/enter-vat-details), it should be 9 or 12 numbers, sometimes with ‘GB’ at the start, like 123456789 or GB123456789.
5. If you are an EU company, the VAT number is not recognized by the EU’s online system. This typically means that the country-level VAT number is not registered. You can work with an accountant to register your VAT number with the EU’s online system. Once that has been done, zero-rate invoices can be applied for all future payments.
If none of the above applies, please contact our Support team and ask them to regenerate your invoice.
## If I add my VAT number after signing up, can Sevalla refund the VAT charge?
Unfortunately, Sevalla cannot refund VAT charges. You will need to work with your accountant to claim it back later.
Regulations on VAT apply at the time of payment. This means if we don’t have a valid VAT number at the time of payment, we are required to collect and pay VAT. Since we can’t receive a refund on VAT, we cannot refund it to you.
## What currency will I be charged in?
You will be charged in US Dollars (USD). Your credit or debit card charge will be converted into your currency when deducted from your account.
## What payment methods do you accept?
We accept credit and debit cards with Visa, Mastercard (including Maestro), Discover, and American Express logos. We also accept AmazonPay and Cash App.
## When do you charge my card?
Your card will be charged on the 1st of every month.
## Can I move or change my billing date?
Yes, to change your billing date, please [contact our Billing team](/support/contact-support/).
## Can I pay my invoice in advance or add a credit to my account?
Our payment provider, Stripe, doesn’t support this. Therefore, we can’t accept advance payments.
## Can I roll over any unused resources to the next month?
No. Unused resources cannot be credited or transferred to the next month.
## How do I use my cross-border credit card?
If you are using a cross-border credit card, you may not be able to input your zip code when adding a new card in Sevalla. For example, if you are a resident of Canada using an American credit card, and your zip code is M4B 1B3, you will need to input the zip code in the following manner.
1. Remove all letters from the zip code.
2. Add two zeros at the end of the zip code.
For example, M4B 1B3 should be entered as 41300 when adding a cross-border credit card in Sevalla.
## Is there a long-term hosting contract?
Nobody likes a long-term hosting contract, and neither do we. There are no long-term contracts at Sevalla; you can [cancel your subscription](/company-settings/delete-company) anytime.
## How do I cancel my subscription?
You can cancel your Sevalla subscription yourself by deleting your company. First, delete all projects and services in the company, then go to **Company settings** > **Billing** > **Danger zone** > **Delete company**. Your subscription is cancelled and your final balance is settled immediately: any unbilled usage is charged to your default payment method, and balances of \$1 or less are forgiven. Only the Company Owner can delete a company. For the full walkthrough, refer to [Delete company](/company-settings/delete-company).
# Static site pricing
Source: https://docs.sevalla.com/billing/static-site-pricing
View detailed pricing information for static site hosting.
At Sevalla, you can add up to 100 Static Sites to your account. Static Site Hosting is free for the first 100 GB of bandwidth per month and 600 build minutes per month; after that, pricing is usage-based. This means that you only pay for resources if your sites exceed the free limits. You can estimate your monthly costs with the [Sevalla pricing calculator](https://sevalla.com/pricing/calculator/) before you deploy. Billing cycles run from the 1st day of the month to the 1st day of the following month, and if you exceed the free limits, we charge your default payment method on the 1st of each month for the previous cycle's usage.
If your static sites exceed the free limits, the billing amounts are included in the **Spending overview** chart on your Sevalla Dashboard. This chart shows the spending overview for all Sevalla services.
For detailed information about your static site costs, the **Usage** page within **Company settings** provides complete visibility into your resource consumption and costs for both the current and previous billing periods across all your services.
Your invoice will be based on the following:
* Bandwidth (egress only)
* Build time
## Bandwidth
We charge for bandwidth flowing out of your sites to the user (egress). After the first 100 GB of bandwidth in a month per account, Sevalla calculates and bills on a per-byte basis at a price of $0.0000000001 per byte ($0.1 per GB). This means no rounding or charges based on every “started” Gigabyte. You are only charged for **actual** usage.
## Build time
Sites need to be built in secure, isolated environments and require resources such as RAM, CPU, and disk to be available. At Sevalla, Static Site Hosting includes 600 minutes of free build time per month per account. Beyond these 600 minutes, additional build time is billed at \$0.05 per minute.
# Tax, VAT, and GST
Source: https://docs.sevalla.com/billing/tax-vat-gst
Find out if you are subject to tax, VAT, or GST and how to add your VAT number, or GSTIN.
To comply with tax regulations, Sevalla charges sales tax, VAT, or GST as required for customers located in certain locations.
Please note that **this article does not constitute legal**, **tax-related**, or **other professional advice**.
If you have questions about adding your tax exemption certificate, VAT number, or GSTIN identification to our system, please contact our [Support team](/support/contact-support/) at any time. If you have further questions about tax or VAT, please contact your accountant, legal advisor, or local tax authority.
## Locations subject to tax
* [US Sales tax](#us-sales-tax) is applied to your invoice if you reside in or your company is registered in Connecticut, the District of Columbia (DC), Ohio, Tennessee, Texas, or Washington State.
* [EU and UK VAT](#vat-value-added-tax) is applied if you are an EU or UK resident or your company is registered in the EU or UK.
* [Indian GST](#indian-gst-goods-and-services-tax) is applied if you are a resident of India or if your company is registered in India.
## US sales tax
To comply with US tax regulations, Sevalla adds sales tax to invoices for customers located in some states in the United States based on the billing address within [Billing details](https://docs.sevalla.com/billing/billing).
Sales tax is a consumption tax imposed by the government on the sale of goods and services. Sales tax is governed by states and may also be charged by local municipalities, so the **percentage may vary from one city and state to the next**. You can read more about sales tax at [usa.gov](https://www.usa.gov/state-taxes).
If you are a US resident or your company is registered in the US, we are obliged to apply sales tax to your purchases if you are located in a state that requires it ([see list above](#states-affected-by-us-sales-tax)).
### States affected by US sales tax
Sales tax is calculated and applied based on the location where services are performed. We determine where our services are being used by looking at the address you provide when you sign up. [You can review and update this address in Sevalla](https://docs.sevalla.com/billing/billing).
Sales tax will be applied to the invoices of customers utilizing our services in any of the following states:
* Connecticut
* The District of Columbia (DC)
* Ohio
* Tennessee
* Texas
* Washington State
**Additional states will be added to this list over time.** When it is determined that Sevalla will need to collect sales tax in an additional state, we will update affected customers prior to implementing the change.
### Sales tax exemption
Under certain circumstances, you or your company might be eligible for a sales tax exemption. Sales tax exemptions are handled on a state-by-state basis. If your organization is exempt from sales tax, please [contact our Billing team](/support/contact-support/) and provide a copy of your **tax exemption certificate.**
For more information regarding tax exemptions, check with your state’s Department of Revenue.
## VAT (Value-Added Tax)
In order to comply with tax regulations, Sevalla charges VAT (Value-Added Tax) to EU and UK residents and to EU and UK-based companies.
VAT is a form of tax that you must pay after the purchase of most goods or services in the EU or UK. This includes digital services such as hosting. VAT is a percentage of the price that is added to each invoice. The VAT rate is defined by each country. Depending on which country you reside in or your company is registered in, the VAT rate will be different.
Data on the specific VAT rates is published regularly. Note that each country can set multiple VAT rates. Our services fall under the **standard rate**. To view specific rates, see your governing body’s official page:
* [EU VAT rates](https://europa.eu/youreurope/business/taxation/vat/vat-rules-rates/index_en.htm#inline-nav-6)
* [UK VAT rates](https://www.gov.uk/vat-rates)
### Zero rate VAT
If you provide a valid VAT Number, we are allowed — under applicable tax rules — to **zero rate** VAT. This means that we will charge 0% VAT. If you have a VAT number, you should add it during registration or in [Sevalla](https://app.sevalla.com/) (**Company settings** > **Billing**) to ensure VAT is not charged to you. As a VAT-registered business, you will still be responsible for VAT under the reverse charge mechanism of your country.
### Add a VAT number
You can add your VAT number at any time within **Company settings** > **Billing** > **Manage billing** > **Update information**. This opens the Stripe platform. In **Tax ID**, choose **XI VAT** for the UK, enter your VAT number, and click **Save**. Note that this can take on many formats, as each member state determines its own format. See the relevant format guide for more information:
* EU VAT Numbers start with the issuing country’s two-letter code. See the [EU VAT Number Format Guide](https://taxation-customs.ec.europa.eu/taxation/vat/vat-businesses/vat-identification-numbers_en) for more information.
* [UK VAT Numbers](https://www.tax.service.gov.uk/check-vat-number/enter-vat-details) are 9 or 12 numbers, sometimes with ‘GB’ at the start, like 123456789 or GB123456789.
Your VAT Number will be validated using the appropriate system (VIES for the EU, HMRC for the UK). It will only be accepted if its format is valid and active in the applicable system. Once you have entered a valid VAT Number, the VAT and total amount will be adjusted, and you will not be charged VAT on future invoices.
## Indian GST (Goods and Services Tax)
In order to comply with tax regulations, Sevalla collects Indian GST (Goods and Services Tax) if you are a resident of India or if your company is registered in India.
GST is an indirect tax charged on most goods and services in India. Sevalla’s hosting service falls under India’s GST category of Online Information Database Access and Retrieval services (OIDAR) to customers in India.
### GST exemption
If you [add a valid GST Number in Sevalla](#add-a-gstin) from the same state shown in your billing address, you will not be charged GST. You will still be responsible for reporting and paying GST on our services under the reverse charge mechanism in India.
If you’ve already added your GSTIN but your upcoming invoice still shows a GST charge, check the following:
1. Make sure the GSTIN is from the same state shown in your billing address.
2. [Verify your number](https://www.gst.gov.in/) on the GST portal and make sure it is valid.
### Add a GSTIN
You may add your GSTIN at any time within **Company settings** > **Billing** > **Manage billing** > **Update information**. This opens the Stripe platform. In **Tax ID**, choose **IN GST**, enter your number, and click **Save**. Your GSTIN will be validated and will only be accepted if its format is valid and active. To be considered valid, the GSTIN must be from the same state shown in your billing address.
Once you have entered a valid GSTIN, the GST and total amount will be adjusted, and you will not be charged GST on future invoices. Rather, you will be responsible for reporting and paying GST on our services under the reverse charge mechanism in India.
## FAQs
### Will sales tax, VAT, or GST be refunded from past invoices?
Unfortunately, we cannot refund sales tax, VAT, or GST collected prior to having exemption or zero-rate documentation on file. You are responsible for providing us with a copy of your tax exemption certificate, VAT number, or GSTIN at the time of purchase.
### How do I obtain a VAT number?
Regulations are different from country to country. Businesses may apply for a VAT number at any time. Businesses that meet a minimum threshold of income are obligated to apply for one.
Note that many European countries may issue national (non-EU) tax numbers or other tax identification numbers. These are not EU VAT numbers and can not be used to reduce the amount of VAT to be paid.
### How do I obtain a GSTIN?
You can [register for a GSTIN](https://www.gst.gov.in/) on India’s Goods & Services Tax website. For more information on the process, several [user manuals and FAQs](https://www.gst.gov.in/) are available.
### Why does Sevalla, a US company, collect VAT?
In most cases, a company is only responsible for tax liability in a given country if it has a permanent establishment there. However, that is not true for VAT. Companies are required to collect and remit VAT, even if they have no permanent establishment in the EU or UK.
For EU VAT, [according to the International Trade Administration](https://www.privacyshield.gov/ps/article?id=Taxation) at the U.S. Department of Commerce:
> Non-EU providers of electronic goods and services are now required to register with a tax authority in the member state of their choosing and to collect and remit value-added tax (VAT) at the VAT rate of the member state in which their customer is located.
For UK VAT, [according to the UK Government](https://www.gov.uk/guidance/the-vat-rules-if-you-supply-digital-services-to-private-consumers), any business making supplies of digital services to UK consumers must collect and remit UK VAT.
In other words, even though Sevalla is a US company, we are required to collect and remit VAT.
### Why does Sevalla, a US company, collect Indian GST?
Even though Sevalla is located outside of India, India’s GST laws apply to our provision of Online Information Database Access and Retrieval services (OIDAR) to customers in India.
# Usage
Source: https://docs.sevalla.com/billing/usage
View a clear breakdown of spending across all of your services.
The **Usage** page provides complete visibility into your resource consumption and costs for both the current and previous billing periods across all your services, including:
* Applications
* Databases
* Static sites
* Object storage
* Load balancers
You can view the total usage for the current and previous billing periods, see a projected cost for the end of the current period, and compare the two periods with a percentage change to understand how your usage is trending.
The usage chart can be filtered by project, service, or usage type, allowing you to focus on specific costs. You can also drill down into each usage category to view a detailed breakdown by service, including services that have since been deleted.
For further analysis or reporting, you can export the usage data as CSV or JSON, or print it directly from Sevalla.
You can access the **Usage** page within **Company settings**.
# Usage alerts
Source: https://docs.sevalla.com/billing/usage-alerts
Set spending limits and get notified by email when your usage exceeds them.
Usage alerts let you set a spending limit and choose threshold percentages of that limit. When usage in the current billing period crosses a threshold, Sevalla sends an email to the recipients you configure.
You can set alerts at two levels:
* **Company**: tracks total spending across every project, application, database, static site, object storage, and load balancer in your company.
* **Project**: tracks spending for the services that belong to a single project.
You can have one alert configuration for the company and one for each project.
## How alerts work
Each alert configuration has:
* A **spending limit** in USD.
* One or more **threshold percentages** (between 1 and 100, up to 10 per configuration). For example, 50%, 75%, and 90%.
* One or more **email recipients**.
Sevalla checks usage against your alerts every hour. When the current period's usage crosses a threshold, an email is sent to every recipient on the configuration. Each threshold triggers at most once per billing period, so you receive a single notification per threshold even if usage continues to grow.
When the next billing period starts, all thresholds reset and become eligible to trigger again.
## Create a company-wide alert
Click **Company settings** > [Usage](/billing/usage) and then click **Add alert**.
Set the following:
* **Budget limit** - the USD amount from which the thresholds are calculated.
* **Percentage thresholds** - one or more percentages of the limit. Add up to 10 thresholds.
* **Email recipients** - one or more email addresses to notify. Click **Add recipient** to add more email addresses.
Click **Create alert** to save. The alert applies to the total spending of every service in your company.
## Create a project alert
Open the project, go to its [Usage](/projects/usage) tab, and click **Add alert**. The fields are the same as for a company alert, but the thresholds are calculated only against the spending of services that belong to that project.
A project alert is independent of the company alert. If you have both, you can be notified when the project or the company crosses its limit, or both.
## Update or delete an alert
Within the **Usage alerts**, you can:
* **Update:** Change the spending limit, thresholds, or recipients.
* **Delete:** Delete the alert. Once deleted, no further emails are sent for it.
When a project is deleted, its usage alert is removed automatically.
## Notes
* Usage alerts are notifications only. They do not pause, suspend, or limit any of your services when a threshold is reached.
* Thresholds are evaluated against gross usage (including tax) for the current billing period, matching the totals shown on the [Usage page](/billing/usage).
* If you change the spending limit or thresholds mid-period, the new values take effect on the next hourly check. Thresholds that already fired this period stay fired until the next period starts.
# Changelog
Source: https://docs.sevalla.com/changelog
Keep yourself informed about the most recent additions and improvements we’ve made to Sevalla.
## More control over how cron jobs run
Cron jobs now expose two Kubernetes scheduling controls, so a run that hangs can no longer quietly wedge your schedule - the exact situation that used to leave a cron job stuck after a deploy until you recreated it.
**Concurrency policy** - decide what happens when a run is triggered while the previous one is still going:
* `Forbid` (default) - skip the new run until the current one finishes. Nothing changes for your existing cron jobs.
* `Replace` - cancel the still-running job and start a fresh one. This is the self-healing option: a stuck run gets cleared on the next tick instead of blocking every run after it.
**Max run time** - optionally cap how long each scheduled run may take. If a run exceeds it, Kubernetes terminates it. Leave it empty (or set `0`) for no limit.
Both settings live in your [process settings](/applications/processes#cron-job-process) and through the API - see [Create process](https://api-docs.sevalla.com/v3/applications/create-process) and [Update process](https://api-docs.sevalla.com/v3/applications/update-process). They apply to cron processes only.
## Railpack build type (beta)
You can now build your applications with [Railpack](/applications/build-options/railpack), the successor to Nixpacks. Railpack analyzes your repository and builds an optimized container image with zero configuration, powered by BuildKit.
To try it, choose **Railpack** as the build type in your application's build settings (**Settings** > **Build strategy** > **Update build strategy**). It is also available through the public API by setting `build_type` to `railpack`.
Railpack detects and builds Node, Python, Go, PHP, Java, Ruby, .NET, Deno, Rust, and Elixir out of the box. Custom start commands work the same way as with other build types: if your web process has a start command set, it overrides the one Railpack detects.
Railpack support is currently in beta. Nixpacks remains the default build type for new applications.
## Purge your CDN cache in one click
Serving stale content after a deploy or an upload? You can now clear it yourself — no need to wait for the cache to expire or reach out to support.
We've added a new **Cache** section to the settings of both static sites and object storage. Head to **Settings → Cache** and hit **Purge cache** to instantly clear the cached assets served from our global CDN.
* **Static sites** — purges the **CDN/Edge cache** for your site. Reach for it right after a deploy when updated assets aren't showing up yet.
* **Object storage** — purges the **CDN cache** for your bucket, so freshly uploaded or replaced objects are served immediately.
The purge takes effect right away, and you'll get a confirmation the moment the cache is cleared. Available to anyone with update access to the service.
## Faster deploys with clearer upload progress
We've made a round of optimizations to how static sites are deployed, and your deploys are now noticeably quicker. Across **264 sites**, deploy time dropped by **32.84%** on average - the typical deploy went from **82.51s down to 56.6s**. Nothing changes in how you deploy. Push your code as usual and the speedup is automatic.
Deploy logs are clearer, too. You'll now see a live upload progress bar so you can follow exactly how far along your upload is, instead of waiting on a silent step. Each deploy prints the total number of files being uploaded, a progress bar that advances with file count and total size, and a closing summary with the final count, size, and how long it took. If any files fail, they're clearly flagged.
```text theme={null}
⬆️ Uploading 1842 files...
[████████████░░░░░░░░] 60% · 1105/1842 files · 24.3 MB
✅ Uploaded 1842 files (41.2 MB) in 18.7s
```
## AI support agent
You can now chat with an AI support assistant directly from the Sevalla dashboard. The assistant answers questions about the platform and, with your permission, about the services running in your account - it can check deployment status, error logs, database backups, and more, and help you troubleshoot issues. You can also attach screenshots to your messages.
To enable it, go to **Help > AI support**, review the data processing terms, and choose what the assistant can access. Permissions work like API key permissions: pick a predefined role or scope custom permissions to specific resources. Once enabled, every member of your company can chat with the assistant, so grant only the access you are comfortable exposing to all members. Only company owners and admins can enable AI support or change its permissions.
A few things worth knowing:
* The assistant is powered by Anthropic Claude. Prompts and account data are sent to Anthropic only to generate responses and are not used to train their models.
* Enabling AI support creates a dedicated, managed API key for your company. Disabling it revokes the key immediately.
* The assistant hands the conversation over to our human support team whenever needed.
* Without account access, the assistant still answers questions using the Sevalla documentation.
## Bandwidth chart in analytics
Application and static site **Analytics** tabs now include a **Bandwidth** chart alongside the existing request rate, response time, and status code charts. Use it to see how much traffic your service is serving over time and to spot bandwidth spikes.
The same timeframe and filter controls that apply to the other charts apply to bandwidth as well.
## Git LFS support
Applications and static sites can now pull LFS-tracked files when deploying from repositories that use [Git Large File Storage (LFS)](https://git-lfs.com/). Large assets tracked by LFS - such as images, videos, datasets, or model files - are fetched during the build. Previously, deploys from LFS repositories succeeded but only the LFS pointer files were checked out, not the actual file contents.
Git LFS is enabled by default. You can disable or re-enable it from the application or static site **Settings** tab. The same flag is available through the public API as `git_lfs_enabled` on [update application](https://api-docs.sevalla.com/v3/applications/update-application) and [update static site](https://api-docs.sevalla.com/v3/static-sites/update-static-site).
You can also toggle the flag with [Sevalla CLI v1.10.0](https://github.com/sevalla-hosting/cli/releases/tag/v1.10.0):
```bash theme={null}
sevalla apps update {id} --git-lfs-enabled true
sevalla static-sites update {id} --git-lfs-enabled true
```
And in the [Terraform provider v1.1.0](https://github.com/sevalla-hosting/terraform-provider-sevalla/releases/tag/v1.1.0).
## Restart a database
You can now restart a database on demand from the dashboard. Open the database's **Settings** tab and click **Restart database** in the **Danger zone**.
The database is stopped and started again - existing connections are closed and any in-flight queries or uncommitted transactions are aborted. Stored data is preserved. The restart runs in the background and usually completes within a few minutes. The database is unavailable until it finishes.
Restart is available when the database is not suspended, is in a `ready`, `error`, `passwordChangeFailed`, or `restoringFailed` state, and its backup status is `ready`.
The same action is also available through the public API at [`POST /databases/{id}/restart-database`](https://api-docs.sevalla.com/v3/databases/restart-database) and through the [Sevalla CLI](https://github.com/sevalla-hosting/cli) with `sevalla databases restart {id}`.
## Header-based conditions in `_redirects`
Static site `_redirects` rules can now match on incoming request headers.
Add a `Header:Name=value` option at the end of a rule to apply it only when the request carries a matching header. For example, to serve a Markdown version of a page to clients that ask for it:
```text theme={null}
/quickstart/ /quickstart.md 301 Header:Accept=text/markdown
```
Header names are matched case-insensitively.
## Restore a backup to a different database
You can now restore a database backup into a database other than the one it was taken from, making it easier to clone data between environments or recover into a fresh instance without overwriting the source.
When opening the **Restore backup** dialog, choose between:
* **Restore to source** - Replace the current data in the original database with the backup contents.
* **Restore to different database** - Pick any other compatible database in your company as the target.
Target databases must be the same type (for example, PostgreSQL), the same version, and in the same datacenter as the source. The source database is left untouched when restoring to a different target.
## Delete non-empty object storage
You can now delete an object storage bucket even when it still contains objects. Any objects inside are removed automatically as part of the deletion.
Previously, you had to empty the bucket manually before it could be deleted.
## Roll object storage secrets
You can now rotate the access and secret keys on an object storage bucket without taking your clients offline.
Open the bucket's **Settings** tab and click **Roll secret** in the **Details** section. Pick how long the previous keys should remain valid:
* **Now** - Invalidate the old keys immediately.
* **Up to 168 hours** - Keep the old keys working alongside the new ones during a grace period, then expire them automatically.
The new access and secret keys are shown right after rotation. Update your applications and tooling before the grace period ends so they switch over to the new credentials without disruption.
The same rotation is also available through the public API at `POST /object-storage/{id}/rotate-credentials`.
## Onboarding experience
Newly signed-up customers are now greeted by a guided onboarding sheet that helps them get up and running on Sevalla faster.
Open it from the **Get started** button in the top-right corner of the dashboard and pick one of four quick-start paths:
* **Connect your coding agent** - The featured option. Generate and copy an API key directly from the guide, then plug AI tools into the Sevalla MCP server at `https://mcp.sevalla.com/mcp` to manage your infrastructure through prompts.
* **Deploy an application** - Ship your first app from a Git repository in just a few steps.
* **Deploy a database** - Spin up a managed PostgreSQL, MySQL, MariaDB, or Redis instance.
* **Try a template** - Launch a pre-configured, self-hosted app in a single click.
Each path is structured as a checklist, so you can manually tick off steps as you complete them.
It's all part of giving new customers a warmer, more delightful start on Sevalla.
## Navigation revamp
We've revamped the navigation to address the "lost" feeling some users experienced when moving around the dashboard. The main and context menus are now shown together, and the dashboard has been expanded to full width.
## Usage alerts
Set spending limits for your company or individual projects and get notified by email when usage crosses your chosen thresholds.
You can configure:
* A **spending limit** in USD.
* One or more **threshold percentages** of the limit (up to 10 per alert), for example 50%, 75%, and 90%.
* One or more **email recipients**.
Each threshold fires once per billing period, and thresholds reset automatically when the next period starts. See the [usage alerts documentation](https://docs.sevalla.com/billing/usage-alerts) for details.
## Custom headers for static sites
You can now add custom HTTP headers to your static sites by including a `_headers` file in your repository's root directory. Sevalla parses the file and applies matching header rules to responses automatically.
Supported features include:
* **Wildcard patterns** - Apply headers to broad path matches like `/*` or `/assets/*`.
* **Placeholders** - Match single path segments with `:name` syntax for dynamic routes.
* **Rule combining** - When multiple rules match a path, their headers are merged automatically.
* **Common use cases** - Easily configure security headers, caching policies, CORS rules, and more.
Certain platform-managed headers (e.g., `Content-Encoding`, `Server`, `Transfer-Encoding`) are restricted and cannot be overridden. See the [headers documentation](https://docs.sevalla.com/static-sites/headers) for the full list and detailed examples.
## Project Admin role for user management
Project Admins can manage user access within their projects, giving scoped control over who can access project resources without needing company-level permissions.
As a Project Admin, you can:
* **Invite users** -- Add new or existing users directly to your project with a project-admin or project-developer role.
* **Manage project roles** -- Promote, demote, or remove users within your project.
* **Manage service roles** -- Grant or revoke access to apps and databases that belong to your project.
* **Convert access levels** -- Move a single-project user between project-level and service-level access within your project scope.
Project Admins cannot modify company-level users, or affect users with access outside their project.
## Deploy paths for static sites
Deploy paths are now available for static sites, giving you fine-grained control over which file changes trigger a deployment. This is especially useful for monorepos or repositories where not every commit should result in a new deployment.
In the **Deploy** section of your static site settings, click **Update deploy paths** and choose between:
* **Allow paths** - Only trigger deployments when changed files match specific glob patterns (e.g., `/src/frontend/**`).
* **Ignore paths** - Skip deployments when all changed files match specific glob patterns (e.g., `**/*.md`).
Deploy paths can also be managed via the [Sevalla CLI](https://github.com/sevalla-hosting/cli), the [Terraform Provider](https://github.com/sevalla-hosting/terraform-provider-sevalla), and the [REST API](https://api-docs.sevalla.com/) (available on the [Get](https://api-docs.sevalla.com/v3/static-sites/get-static-site), [Create](https://api-docs.sevalla.com/v3/static-sites/create-static-site), and [Update](https://api-docs.sevalla.com/v3/static-sites/update-static-site) static site endpoints).
## Update source for static sites
You can now change the source repository for your static sites directly from the settings page - no need to delete and recreate the site.
Click **Update source** in the **Deploy** section of your static site settings to switch between a private or public Git repository, change the Git provider (GitHub, GitLab, or Bitbucket), or point to a different repository URL.
## App health
Real-time visibility into application health is now available directly in the dashboard. When something goes wrong with your app - whether it's an out-of-memory crash, a segmentation fault, or a misconfigured start command - you'll see an alert banner at the top of the page with actionable details.
Click the banner to open the App health panel, which shows:
* **Instance status at a glance** - See the state of every running instance across all your process types (web, worker, cron, job), including restart counts and exit codes.
* **Automatic issue detection** - Recognized failure scenarios include OOM kills (exit code 137), segmentation faults (exit code 139), permission errors, missing binaries, application errors, and health check misconfigurations.
* **Troubleshooting guidance** - Each detected issue comes with a plain-language explanation and specific steps to resolve it, so you can diagnose problems without digging through logs.
* **Live updates** - Instance statuses refresh in real time, so you can watch recovery happen as you apply fixes.
The alert banner appears across all application pages, so you'll never miss an issue regardless of where you are in the dashboard.
## Usage page
The new Usage page gives you full visibility into your resource consumption and costs directly in the dashboard.
Get a clear breakdown of spending across all your services - applications, databases, static sites, object storage, and load balancers - with daily cost tracking and period-over-period comparison.
Key highlights:
* **Summary cards** - See your current period total, projected end-of-period cost, and previous period comparison with percentage change indicators at a glance.
* **Interactive charts** - Visualize daily or cumulative costs with stacked bar and area charts, color-coded by usage type.
* **Flexible filtering** - Filter by project, service, or usage type to drill into exactly the costs you care about.
* **Detailed cost table** - Expandable table showing per-service net, gross, and tax amounts grouped by usage category, with deleted services clearly marked.
* **Export and print** - Download your usage data as CSV or JSON, or print a full report for your records.
The Usage page is accessible from the Settings section in the sidebar.
## Sevalla Terraform Provider
The official [Sevalla Terraform Provider](https://github.com/sevalla-hosting/terraform-provider-sevalla) is now available. Define and manage your entire Sevalla infrastructure as code using HashiCorp Terraform.
Provision applications, databases, static sites, and configure domains, environment variables, and scaling - all through declarative HCL configuration files. Perfect for teams that want reproducible, version-controlled infrastructure.
## Sevalla CLI
The official [Sevalla CLI](https://github.com/sevalla-hosting/cli) is here - manage your entire Sevalla infrastructure from the terminal.
Deploy apps, provision databases, manage static sites, configure domains, and monitor your services without leaving the command line. Every action available in the dashboard is now at your fingertips via a clean, consistent command structure.
Install it with your preferred package manager:
```bash theme={null}
# Homebrew
brew install sevalla-hosting/tap/sevalla
# npm (Node.js 22+)
npm install -g @sevalla/cli
# Shell script
bash <(curl -fsSL https://raw.githubusercontent.com/sevalla-hosting/cli/main/install.sh)
```
Key highlights:
* **Full platform coverage** - Applications, databases, static sites, domains, and monitoring all in one tool.
* **Scriptable output** - Every command supports `--json` for easy integration with CI/CD pipelines and automation scripts.
* **Flexible authentication** - Interactive browser-based login for local use, or API token via `SEVALLA_API_TOKEN` for automated workflows.
Run `sevalla --help` to explore all available commands, or check out the [GitHub repository](https://github.com/sevalla-hosting/cli) for full documentation.
## Sevalla MCP server
The official [Sevalla MCP](https://github.com/sevalla-hosting/mcp) (Model Context Protocol) server in now available. You can now give AI agents and coding assistants full access to the Sevalla PaaS API.
You can seamlessly connect popular MCP clients like Claude Code, OpenCode, Cursor, and other coding agents directly to our hosted server at `https://mcp.sevalla.com/mcp`. Authentication is handled effortlessly via OAuth, meaning you don't need to hardcode API keys in your configuration files.
Now that your AI can spin up and manage infrastructure on command, the only limit is your imagination. Well, that and your prompt engineering skills. 😉
## Sevalla REST API v3
Sevalla now has a fully featured REST API, giving you programmatic access to everything you can do in the dashboard.
The v3 API covers over 200 endpoints across all major resources - applications, databases, static sites, object storage, load balancers, pipelines, webhooks, projects, and more. Whether you're automating deployments, managing environment variables, or scaling processes, the API has you covered.
Key highlights:
* **Full OpenAPI 3.1 specification** - Interactive documentation with field-level descriptions, examples, and error responses available at [api-docs.sevalla.com](https://api-docs.sevalla.com).
* **Granular API key authentication** - Scope each key to specific roles, resources, or actions using the same RBAC system as the dashboard.
* **Clean, predictable design** - Flat JSON responses, consistent snake\_case naming, and proper HTTP methods make integration straightforward.
* **Built-in rate limiting** - Tiered limits per endpoint type protect your services while giving you plenty of room for automation.
* **Error tracking** - Every server error includes a unique reference code you can share with support for fast resolution.
The API is designed to work well with CI/CD pipelines, infrastructure-as-code tools, and AI-powered workflows.
Explore the full API reference at [api-docs.sevalla.com](https://api-docs.sevalla.com) to get started.
## Load balancers
Sevalla now supports load balancers, giving you full control over how traffic is distributed across your services.
Load balancers run at Cloudflare's edge network, routing requests close to your users for faster, smarter traffic decisions. You can route to applications, static sites, object storage buckets, external URLs, or even other load balancers - up to 20 destinations per load balancer.
Two balancing modes are available:
* **Weighted** - Control the proportion of traffic each destination receives. Useful for canary deployments, A/B testing, or gradual migrations between services.
* **Geographic** - Route users to the nearest destination based on their location, reducing latency for globally distributed setups.
Each destination can be individually enabled or disabled without removing it, and traffic weights are adjustable at any time. Custom domains are fully supported with automatic SSL, alongside an auto-generated Sevalla domain available immediately on creation.
This makes it easier to build resilient, multi-region architectures and manage traffic across services without external tooling.
## Projects usage tab
The project page now features a Usage tab, allowing users to track their service costs and consumption during the current billing period and compare them to the previous one.
## RBAC-protected Projects
As your infrastructure grows, keeping things organized and secure is essential. You can now group your services into Projects within your company workspace.
To give you more control over who can access what, we're also rolling out a new Project Developer role. This allows you to grant fine-grained, project-level permissions to your team members. A Project Developer can fully manage the services within their specific project, but they are completely restricted from seeing or touching resources outside of it.
This makes it simpler to onboard new developers and restrict access without slowing down their workflow\.g
## Granular API key permissions
API keys on Sevalla now support fine-grained permission control, giving you full flexibility over what each key can access and do.
You can assign one of the predefined roles - Company Admin, Company Developer, Company Billing, or Company Viewer - or build a custom permission set tailored to your exact needs. Custom permissions let you select specific actions per resource type and scope them down to individual resources.
For example, you can create an API key that only has view access to a single application, or one that can manage databases but nothing else.
This makes it easier to follow the principle of least privilege across your integrations, CI/CD pipelines, and team workflows.
## Access logs for apps and static sites
You can now view access logs for your applications and static sites directly in the Sevalla dashboard.
Access logs give you visibility into incoming HTTP requests — including request paths, status codes, IP addresses, and response times — so you can monitor traffic, debug issues, and understand how your services are being used.
Whether you're troubleshooting a 404, investigating a traffic spike, or just keeping an eye on things, access logs have you covered.
Head to the Logs section of any application or static site to get started.
## Improved logging experience
We've shipped a major upgrade to Sevalla logging, making it easier to explore, analyze, and export your logs.
* **Structured logs support** - Logs are now stored and displayed as structured data, enabling more precise inspection and analysis.
* **Log export** - Download logs in **JSON** or **CSV** format for offline analysis, audits, or sharing.
* **Advanced filtering** - Filter logs with greater flexibility to quickly narrow down relevant entries.
This update improves both day-to-day debugging and longer-term operational workflows, especially for teams working with higher log volumes.
## Analytics updates
We've shipped improvements across **Sevalla Analytics** to make data exploration faster and more intuitive.
* **Chart zooming** across apps, databases, and static sites
Zooming one chart now shows a **reference line** on other charts on the same page.
* **Application analytics improvements**
* Separate **Compute** and **Web** analytics
* Enhanced Web analytics: **country charts**, **RPM**, **HTTP status codes**, and **improved filters**
* **Static site analytics upgrade**
* Same Web analytics charts and features as applications
These updates make it easier to correlate metrics, investigate traffic patterns, and spot anomalies.
## Single Sign-On (SSO)
You can now sign in to Sevalla using Single Sign-On (SSO). Connect your identity provider and manage team access securely with centralized authentication.
## Global app environment variables
Define global environment variables that can be used across all your applications. These are ideal for shared configurations, such as API keys or global feature flags.
The application-level environment variables page will indicate if any global variables are set and allow you to access them easily.
## Display recently used locations in location selector
Recently used locations will appear first in the location selector, making it easier to reuse the same data centers.
## Utilize \*.proxy.sevalla.app domain for DB ext connection & TCP proxy
Previously, we used `kinsta.app` domain. After toggling a database connection, it now receives a sevalla domain instead. The same applies to app-level TCP proxies.
## Nixpacks version 1.41
Newest Nixpacks version is available under "Build strategy settings".
## Custom port for healthcheck
The update process sheet now includes a custom internal port health-check setting, allowing you to specify port numbers for either the Readiness or Liveness probe.
## Database public access with IP restriction
Users can now enable external database access with fine-grained control. Previously, connections were either fully open or completely disabled, now you can allow or block access based on specific IPs or IP ranges.
We also introduced a new Networking tab under database, where you’ll now find the external connection toggle, IP restrictions, and connected apps.
## Deployment updates log
You can now view application changes in the Deployments table. Each deployment shows when the updates went live, along with a small badge indicating the number of changes. Detailed information is available on the Deployment details page.
## Create webhooks to receive service event notifications
You can now configure an endpoint to receive event notifications when changes occur in your apps, databases, or static sites.
Each webhook request includes an `svl-signature` header for verification, and failed deliveries are retried up to 12 times, with all attempts visible in the **Event Deliveries** view.
Initial supported event types include:
* `APP_CREATE`, `APP_UPDATE`, `APP_DELETE`, `APP_DEPLOY`
* `DATABASE_CREATE`, `DATABASE_UPDATE`, `DATABASE_DELETE`
* `STATIC_SITE_CREATE`, `STATIC_SITE_UPDATE`, `STATIC_SITE_DELETE`, `STATIC_SITE_DEPLOY`
Learn more in the [documentation](https://docs.sevalla.com/tools/webhooks).
## Pretty URLs for static sites
Static sites on Sevalla now support Pretty URLs, which automatically standardize URLs for cleaner paths and improved SEO.
When enabled, Sevalla will:
* Redirect paths like `/about` → `/about/`
* Rewrite paths like `/about.html` → `/about/`
This behavior helps ensure consistent URL structures and better caching performance across our CDN.
You can enable Pretty URLs in your project's **Static Site** > **Settings** > **Redirects** section.
## \_redirects file support for static sites
Static sites on Sevalla now support the `_redirects` file format. If your repository includes a `_redirects` file in its root, Sevalla automatically parses and applies your custom redirect rules.
Supported features include:
* **Custom 404 pages**: Add a `404.html` page, and Sevalla will automatically serve it for missing paths.
* **Force redirects**: Use `!` in your status code to override existing files, ensuring your redirect always takes effect.
* **Splats**: Use wildcards (e.g. `/news/* → /blog/:splat`) to match entire path segments.
* **Placeholders**: Dynamically capture path segments using variables like `:slug` or `:id`.
* **Query parameters**: Match redirects based on query strings (e.g. `/store?id=:id → /blog/:id`).
These additions make it easier to manage complex routing logic directly from your repository with no extra configuration required.
For single-page applications that rely on client-side routing, we recommend adding the rule `/* /index.html 200` so that all paths correctly return `index.html` with a 200 status instead of a 404 on reload.
## A brand-new Sevalla dashboard (with dark mode!)
The wait is finally over.
We’ve refreshed Sevalla’s look and feel with a cleaner, more modern design and packed it with visual and usability improvements.
The highlight of this release is **Dark Mode** 🌙, giving you a sleek, eye-friendly experience whether you’re coding late at night or just prefer a darker interface.
A big thank-you to all our beta users who helped us test and refine the new interface. We’re thrilled to share it with everyone, and as always, if you spot any quirks, we’d love your feedback.
## Redis 8 support enabled
Great news! Redis 8 is now available on Sevalla!
We've officially enabled Redis 8 so you can start using the latest version in your apps.
Upgrade today to benefit from improved performance, stability, and new Redis 8 features.
## Docker caching is now available
We've expanded our build caching options! 🚀
In addition to Nixpacks and Buildpacks caching, you can now take advantage of Docker layer caching.
This helps speed up your deployments by reusing unchanged Docker layers, resulting in faster builds and more efficient pipelines.
## Faster app hibernation wake-up
Hibernated apps now wake up much faster, so your app becomes responsive more quickly after a period of inactivity. Previously, apps could take 60–90 seconds to start up after being idle, but now they’re ready in just 8–20 seconds.
Keep in mind that your app needs a redeploy to activate the new hibernation settings.
## Nixpacks version selection is here
You can now select your preferred Nixpacks version for your apps on Sevalla. This gives you more flexibility and control over your deployments, and helps ensure smooth upgrades.
Starting today, all newly created apps will use Nixpacks version 1.39 by default (previously 1.29). If you need to use a different version, simply choose the version that best fits your project.
## System environment variables available in applications
We're introducing automatic injection of several system environment variables into your apps during both build and runtime. This makes it easier to automate tasks and access important deployment details directly from your application.
The following environment variables will be available:
* SVL\_COMPANY\_ID
* SVL\_APP\_ID
* SVL\_APP\_NAME
* SVL\_DEPLOYMENT\_ID
* SVL\_DEPLOYMENT\_INITIATED\_BY
* SVL\_DEPLOYMENT\_TRIGGER
* SVL\_DEPLOYMENT\_COMMIT\_SHA
* SVL\_DEPLOYMENT\_BRANCH
* SVL\_DEPLOYMENT\_DOCKER\_IMAGE
Use these variables for enhanced automation and more flexible app behavior!
## Sevalla official GitHub action
GitHub users can now seamlessly integrate Sevalla deployments into their workflows, just add the official Sevalla GitHub Action to your pipeline and deploy with ease.
[View on GitHub Marketplace](https://github.com/marketplace/actions/sevalla-deploy)
## App analytics improvements
Your feedback is invaluable! We've supercharged the app analytics section with some highly-requested features:
* Charts now auto-refresh, giving you real-time insights!
* Easily track RAM/CPU limits over time.
* Clearly see your processes' instance counts as they scale up or down.
## Updated documentation pages
We’ve just updated our documentation with a refreshed design and enhanced features to make onboarding even smoother. ✨
* Both documentation sites now share a unified, modern look
* Fully compatible with AI crawlers
* AI-powered search assistant is now available
Links:
* [docs.sevalla.com](https://docs.sevalla.com)
* [api-docs.sevalla.com](https://api-docs.sevalla.com)
## Sevalla domains can be updated
You can change your generated domains at any time. This is useful for testing or if you want to use a different domain name for your app or static site.
## 1-click deployable templates are now available
You can now deploy your applications using 1-click deployable templates. This feature allows you to quickly set up and deploy self-hosted, open-source applications with pre-configured settings, making it easier than ever to get started with your projects.
You can find the "Templates" menu item on the Sevalla UI. Simply select the template you want to use, and click "Deploy". The application will be set up and running in no time.
Our list of templates are constantly growing, so be sure to check back often for new additions. If you have any suggestions for templates you'd like to see, please let us know over support, or on [our Discord server](https://discord.gg/sevalla)!
## Object storage CORS settings
You can add CORS settings to your object storage buckets, allowing you to control how resources are shared across different domains.
## Connected services on app overview diagram
You can enable internal network connections between resources, and this is now visually represented in the application overview diagram.
## Deployment status indicator in favicon
The deployment status appears directly in your browser tab, allowing you to quickly see whether it's in progress or complete without switching tabs.
## Wildcard domains
You can now use wildcard domains for your apps and static sites. Perfect for things like custom subdomains (`*.yourdomain.com`) or multi-tenant setups. Just add your wildcard domain, and we'll take care of the rest - automatic SSL included.
## Database Studio
You can now manage your MySQL, MariaDB, and PostgreSQL databases directly from the Sevalla UI. Run custom SQL queries, browse and download data, and take full control of your database - no external tools needed.
## App build settings revamped
We've given the App Build settings tab a complete makeover! Beyond the sleek new interface, we've introduced three functionalities:
**New features:**
* **Docker registry credentials** — Now you can seamlessly connect to private registries for your Dockerfile base images
* **Buildpack builder selection** — Conveniently update your builders:
* `heroku/builder:22`
* `heroku/builder:24`
* **Build environment visibility** — We've added visibility for build environment settings associated with each deployment, and included a button for easy modification of those settings above the deploy logs
## PostGIS is now available for our PostgreSQL databases
Many of you have asked for PostGIS support, and we're announcing that it's now available for PostgreSQL 13+ databases!
PostGIS is a spatial database extension for PostgreSQL, allowing you to store and query geographic information. With PostGIS, you can:
* Store and manage spatial data types like points, lines, and polygons
* Perform spatial queries to analyze and visualize your data
* Build location-aware applications and services
To enable PostGIS, simply create a new PostgreSQL 13+ database and make sure you tick the "PostGIS" option during the creation process.
## Deploy hooks
We're excited to introduce Deploy hooks, making automated deployments even easier!
With Deploy hooks, you can now trigger deployments with a simple POST request to a unique URL, perfect for integrating with your workflow. This powerful feature enables:
* Seamless CI/CD integration: Connect your GitHub Actions, Jenkins, or other CI tools
* Automated deployments: Trigger updates when your content or data changes
* Custom workflow support: Build scripts that deploy your apps when needed
## IP access controls for applications
We've just rolled out powerful new IP restriction capabilities for your app hosting environments:
* **IP Allowlists**: Create a trusted circle of approved IP addresses
* **IP Denylists**: Block specific troublesome IPs or ranges
Both features support individual addresses or CIDR notation for precise network control. Simply choose which approach works best for your security model (note: only one mode can be active at a time).
This highly-requested security enhancement gives you granular control over who can access your applications.
## Preview apps now support advanced pre-configuration
You can now pre-define your preview apps with both disk configurations and TCP proxies right from the start.
We've also published the ["createPreviewApp"](https://api-docs.sevalla.com/v3/pipelines/create-pipeline-stage) endpoint in our public API, enabling programmatic creation of fully-configured preview environments.
## Vector search with pgvector has arrived
We've just integrated [pgvector](https://github.com/pgvector/pgvector) extension support for PostgreSQL databases (version 11+).
This powerful addition enables:
* Lightning-fast vector similarity searches
* Seamless RAG (Retrieval-Augmented Generation) implementations
* Enhanced AI application capabilities right in your database
## Choose your shell in Web terminal
App hosting users, you can now select between three powerful shell types:
* `sh` (for minimalists)
* `bash` (the classic choice)
* `zsh` (for the feature lovers)
Simply choose your preferred shell when launching a terminal session and enjoy a more personalized development experience. Don't worry - if your selected shell isn't available in the container, you'll get a friendly notification so you can choose another option.
## Object storage with S3 compatibility
Our new object storage solution provides unlimited scalability for all your application needs, with zero ingress and egress fees, powered by Cloudflare R2.
Key Features:
* S3-Compatible API: Seamlessly integrate with your existing S3 workflows, making migration and management effortless.
* Global Availability: Choose from 6 global storage locations to optimize data access and comply with data residency requirements.
* Transparent Pricing: Enjoy predictable costs at just \$0.02 per GB per month, with no hidden fees.
## Resource limits in analytics charts
Never hit unexpected resource ceilings again! You can now see your service's configured limits displayed directly on the Analytics charts alongside actual usage metrics.
This visual enhancement helps you:
* Spot when you're approaching capacity limits
* Make data-driven scaling decisions
* Optimize resource allocation for cost efficiency
Check out your App and Database analytics today to see this improvement in action!
## Custom time zone setting for cron jobs
Teams working across the globe! You can now set custom IANA time zones for your cron jobs instead of being locked to UTC.
## Manual cron trigger functionality
You can now manually trigger your cron processes directly from the Sevalla dashboard with just one click.
## Resource usage breakdown chart
Company-level users can visualize daily spending patterns, giving you visibility into where your resources are going.
Key benefits:
* Track spending trends across different cost categories
* Identify cost optimization opportunities at a glance
* No more guesswork about your platform costs.
## Database connection deeplink
Connect to your database instantly with a single click.
No more copying connection strings or credentials.
Hit the new "Open deeplink" button in the external connection card and watch as your local machine connects seamlessly to your database.
## Email notifications for failed deployments
New email notification system for failed deployments across both applications and static sites.
Now you'll instantly know when something goes wrong, allowing you to address issues before they impact your users.
Simply manage your notification preferences under **User > Notifications** to tailor the experience to your needs.
## gRPC support has landed
We shipped `gRPC` support for your applications, unlocking high-performance communication.
Now you can easily toggle between `HTTP` and `gRPC` protocols for your web processes.
## Private network access for builds
Build pods can now securely reach other resources via a private network. Perfect for running database migrations during build time. Enjoy a smoother, more efficient workflow!
## Support env var reference
You can now reference environment variables within other variables using the `${key}` format.
For example:
```text theme={null}
API_URL=https://api.example.com
FRONTEND_URL=${API_URL}/frontend
```
## MySQL 9.0 is available
The long-awaited new version of MySQL is here.
MySQL 9.0 brings a host of new features and improvements, including:
* JavaScript stored programs
* VECTOR data type
* Foreign key improvements
* Performance schema enhancements
* Query optimization
## Expose non-HTTP traffic via TCP proxy
We're announcing support for exposing non-HTTP traffic via TCP proxy.
Now it's effortless to expose services like databases or message queues. Deploy MongoDB, RabbitMQ, and more with ease.
## PostgreSQL 17 is here
PostgreSQL 17 is now available on Sevalla.
Benchmarks claim 20-30% better query performance compared to the previous version.
v17 also brings a bunch of new features and improvements. For more details, check out the [official release statement](https://www.postgresql.org/about/news/postgresql-17-released-2936/)!
## Control database public access
Going forward, every database you create will be private by default.
Toggle public availability of your database on the fly, so feel free to do so whenever you need to.
## Undeployed change-set notifications
We received feedback that it was unclear which actions on Sevalla triggered a deployment and which did not.
You're in control when you'd like to initiate a full rebuild of your app, or just restart it with some fresh configs.
## Revamped environment variables management
We made a major overhaul of our environment variables management in our application hosting product.
You're now able to:
* Export/import variables to/from a file
* Copy all environment variables to the clipboard
* Display the user and timestamp of recent updates/creations
* Copy key-value pairs directly from the table
* Use the new editor in the "Add Network" modal
## Configure CDN / Edge cache settings
Until now, configuring your app's CDN and edge caching settings required a trip to our API.
You can now effortlessly manage these settings directly from your dashboard, under **App > Networking** settings.
## Hibernate your apps to save costs
We're excited to introduce a new feature that will help you save money on your hosting costs.
With our new [Hibernation feature](https://docs.sevalla.com/applications/settings#hibernation), you can now put your applications to sleep when they're not in use. This means you can save on compute resources and only pay for what you use. It's a great way to reduce your hosting costs without sacrificing performance or reliability.
Here's how it works:
* When you hibernate an application, we'll scale down your application's all long-running pods to zero replicas.
* When a request comes in, we'll automatically wake up your application and start serving traffic again.
Hibernate is perfect for applications that have low or intermittent traffic, like side projects, or test environments. You can now save money on hosting costs without having to worry about downtime or performance issues.
## Go fully private
We're thrilled to announce a major update that's all about security! 🔒
As part of our ongoing commitment to protecting your workloads, we've introduced a new feature that exposes private ports & disables ingress on web processes. This means you now have the power to decide who can access your applications and services, and how they can interact with each other.
With this update, you can:
* Expose private ports internally, making it easier to build and run microservices, or integrate services like RabbitMQ or databases that require internal communication.
* Disable ingress on web processes, giving you granular control over who can access your applications and services, and how they can interact with each other.
We're proud to bring you this update, and we're confident that it will help you build and run your applications with even more security and control.
## Sevalla is now ISO 27001 certified
We have earned the coveted ISO 27001 security certificate!
Achieving ISO 27001 certification is no small feat, and it's a testament to the hard work and dedication of our team.
## Utilize deployment hooks with Jobs for application hosting
We're excited to introduce a new process type called, `Job` in our [application hosting](/application-hosting/)! This feature makes it easy to send alerts and perform database migrations for exmaple.
No more manually appending scripts in your start commands - just set up your Job and let it run! You can configure when jobs should run:
* before deployments
* after successful deployments
* after failed ones
## Static site pull request previews feature
We're thrilled to introduce the pull request previews feature, which lets you preview your sites in a dedicated environment before merging them into your default branches.
No more worries about broken links or layout issues - previews ensure a seamless experience for you and your team!
## Static site build logs improved
Debugging your [static site](/static-site-hosting/) builds just got a whole lot easier! We've unleashed a fresh, revamped log structure that's designed to make your life easier. Our new and improved logs are now more readable, organized, and packed with extra context to help you troubleshoot issues!
But that's not all, folks! We've also squashed a pesky node modules path issue that was causing some users to experience a `"Command not found"` error when trying to run commands directly. No more frustration - our fix means you can get back to building and deploying your static sites with ease!
So, what's changed? Our log format has gotten a makeover, with improved formatting, clearer categorization, and additional context to streamline the debugging process. And, behind the scenes, we've made sure that `node_modules` paths are now correctly resolved, so you can focus on what matters most - building fantastic static sites! 🚀
## Analytics overhaul
We're stoked to announce a major overhaul of our analytics charts for [apps](/application-hosting/), [databases](/database-hosting/), and [static sites](/static-site-hosting/)! We've taken a hard look at our infrastructure and chart library, and the result is a completely new and improved experience. Say goodbye to slow data fetching and hello to almost real-time updates, thanks to our latest infrastructure ✨wizardry✨ (hello, Prometheus!).
Here's what's changed:
**Compute data**: We've ripped out the old and replaced it with a brand new, Prometheus-powered system that delivers lightning-fast data and virtually instantaneous updates.
**HTTP data**: No more waiting around for hours! Our new latency is a mere 1-3 minutes, making it easier to spot trends and troubleshoot issues.
**New visuals**: We've swapped out our old chart library for a fresh, improved experience that's easier to use and understand.
And, static site hosting gets in on the action too! You'll now find an Analytics tab, showcasing essential metrics like:
* Requests per minute
* Response time
* Slowest requests
* Top pages
We've also made some behind-the-scenes changes to simplify things and remove clutter. We've merged response time charts (`p90`, `p95`, `p99`, `avg`) for a clearer view and removed runtime charts, as they were more relevant to billing than observability. And, to simplify things, we've hidden `HTTP` charts for processes that aren't exposed.
## Hello world! Welcome to Sevalla
We're your partner in building amazing applications, a platform-as-a-service (PaaS) designed specifically for developers like you, who want to focus on writing code, not managing infrastructure. With Sevalla, you can host your application, managed database, and static site all in one place, and get the scalability, reliability, and security you need to succeed.
We believe that building software should be fun, not frustrating. That's why we're dedicated to providing a seamless development experience, with easy deployment, and automated scaling. Whether you're building a simple web app or a complex enterprise solution, we've got you covered.
So why choose Sevalla? Here are just a few reasons:
* Focus on code, not infrastructure: With Sevalla, you can leave the heavy lifting to us, and focus on what you do best - building great software.
* Scalability and reliability: Our platform is designed to handle sudden spikes in traffic, and our automated monitoring ensures that your app is always available.
* Security: We take security seriously, with access controls, and regular security audits.
* Flexibility: Choose from a range of hosting options, including application, managed database, and static site hosting, to find the solution that's right for you.
Don't forget to keep an eye on our changelog, where we'll be announcing new features, improvements, and other exciting developments. We're always working to make Sevalla better, and we want you to be the first to know about the latest and greatest from our platform.
# Delete company
Source: https://docs.sevalla.com/company-settings/delete-company
Cancel your Sevalla subscription and permanently delete your company.
If you’re having trouble with your site, application, or database, or have questions about your plan, please open a new chat with our team. We’re here for you and are happy to help!
We understand there are some cases where you may need to cancel your Sevalla subscription and delete your company. Maybe you wanted to test Sevalla out, or no longer need your site or application. Whatever the reason, you can delete your company yourself, directly from the dashboard - no support ticket needed.
Deleting a company is a two-part process:
1. Delete all projects and services in the company.
2. Delete the company from **Company settings** > **Billing** > **Danger zone**. This cancels your Sevalla subscription and settles your final balance immediately.
If this is your only company, you can also [delete your user account](/user-settings/delete-account) in the same step.
## Delete your projects and services
Only Company Owners and Company Administrators can delete a site, application, database, or object storage container. For information about how to change a user’s access, refer to [User Management](/company-settings/user-management).
A company cannot be deleted while it still contains any projects or services. This includes applications, databases, static sites, object storage, load balancers, and pipelines. If anything remains, the deletion dialog lists exactly what you still need to remove.
### Applications
When you delete an application, it **completely removes** the following:
* All files
* Settings
* Persistent storage disks
* Connections to other applications or databases.
To delete an application, click **Applications** > ***app name*** > **Settings** > **Danger zone** > **Delete app** > **Continue**.
[Application pricing](/billing/application-pricing) is usage-based; therefore, you simply pay for the time used at the end of your billing cycle.
### Databases
When you delete a database, all of the data in the database is destroyed. It also removes any disk space add-ons attached to the database.
To delete a database, click **Databases** > ***database name*** > **Settings** > **Delete database** > **Continue**.
[Database pricing](/billing/database-pricing) is usage-based; therefore, you simply pay for the time used at the end of your billing cycle.
### Static sites
When you delete a static site, it completely removes all of the associated files and settings. You cannot recover a site in Sevalla once it is deleted.
To delete a static site, click **Static Sites** > ***site name*** > **Settings** > **Danger zone** > **Delete static site** > **Continue**.
### Object storage
Deleting your object storage bucket permanently removes the bucket, all stored objects, and any associated credentials. Once deleted, the bucket and its contents cannot be recovered.
To delete an object storage container, click **Object storage** > ***object storage name*** > **Settings** > **Delete object storage** > **Continue**.
### Load balancers, pipelines, and projects
Load balancers and pipelines must also be removed before you can delete the company. Delete them from the settings of each resource. Finally, delete any remaining (empty) projects from the project settings.
## Delete your company
Only the Company Owner can delete a company. Deletion is immediate and cannot be undone.
To delete your company:
1. Log in to [Sevalla](https://app.sevalla.com) as the **Company Owner**.
2. Go to **Company settings** > **Billing** and scroll to the **Danger zone**.
3. Click **Delete company**.
4. Tell us why you are leaving. Select a reason and, optionally, share any feedback, then click **Continue**.
5. Review what happens when the company is deleted. If this is your only company, you can also select **Also delete my user account**.
6. Type the company name to confirm, and click **Delete company**.
If the company still has projects or services, the dialog lists what you need to remove first instead of the confirmation form. Delete the listed resources and try again.
## What happens when you delete a company
* Your Sevalla subscription is cancelled, and your final balance is settled immediately. Any unbilled usage is added to a final invoice, and remaining credits are applied first. Final invoices over \$1 are charged to your default payment method; smaller balances are forgiven.
* The company and all of its data are deleted right away. This cannot be undone.
* Links to previously issued invoices and receipts remain valid, so you can still access your billing history.
* If you belong to other companies, your user account is kept, and you are switched to one of your remaining companies.
* If you selected **Also delete my user account**, your user account is deleted after the company, and you are logged out. Refer to [Delete account](/user-settings/delete-account).
If the final payment fails, the company is not deleted. Update your [payment method](/billing/billing#payment-methods) to settle the outstanding balance, then try again. For more information, refer to [Failed payments](/billing/failed-payments).
## Companies shared with MyKinsta
Sevalla and [MyKinsta](https://kinsta.com) can share the same company. If your company also has a WordPress hosting plan or WordPress sites in MyKinsta, deleting the company from Sevalla only cancels your Sevalla subscription and removes your Sevalla billing. The company itself, your user account, and everything in MyKinsta remain untouched.
## Transfer instead of delete
If you want to keep the company running under someone else, you can transfer it to another user instead of deleting it. Refer to [Transfer company ownership](/company-settings/overview#transfer-company-ownership).
# Company Settings - Overview
Source: https://docs.sevalla.com/company-settings/overview
Get an overview of your company settings.
Sevalla uses companies to associate users with applications and databases hosted on our platform. Understanding how companies work at Sevalla will help you understand how you can work with multiple users, applications, or databases on our platform.
Think of companies as the central point in this arrangement that users and sites revolve around:
* Each application, database, or site belongs to just one company.
* You, as a user, can have access to one or more companies.
* You can invite other users to your company, application, database, or site.
Within company settings, you can access:
* [Billing information](/billing/billing) - Amend your company name or address, add payment methods, and view your invoices.
* [Usage report](https://docs.sevalla.com/billing/usage) - To view the resource consumption and costs across all your services.
* [User management](/company-settings/user-management/) - Grant other users access to your company, manage their access level, or grant access to individual applications, databases, or sites.
* [Single sign-on](https://docs.sevalla.com/company-settings/single-sign-on/overview) - Set up SAML SSO to securely access multiple applications using a single set of credentials.
You can access the company settings within **Company settings**.
## Update your company name
To update or change your company name in Sevalla, click on your company name and then click **Update company name**.
This only updates the company name shown in Sevalla. It does not update your billing information. To change your billing details, go to **Settings** > **Billing** > **Manage billing**.
Enter the new company name and click **Update company name**.
## Create a new company
If you are working with multiple clients or agencies, you may want to create an additional company for your sites and then grant access to the company. You can create up to 10 companies within Sevalla.
To create a new company, click on your company name and then click **Create new company**.
Add your company name, and click **Create company**.
Enter your payment method and billing details, and then click **Complete setup**.
After creating the new company, you can see which company you’re viewing and switch between companies at the top of any page in Sevalla.
You can then [invite users to your company](/company-settings/user-management/#invite-a-user).
If you want to remove a user, refer to [remove a user from a company](/company-settings/user-management/#remove-a-user-from-a-company).
## Transfer company ownership
Only **Company Owners** can transfer company ownership to a **Company Administrator** in the same account. Each company can have only one owner, but ownership can be transferred between users.
To transfer ownership to another user:
* You must be logged in to [Sevalla](https://app.sevalla.com) as the **Company Owner**.
* The user you want to transfer ownership to must be a **Company Administrator**.
Log in to [Sevalla](https://app.sevalla.com) and go to **Company settings** > **User management**. Click the ellipsis (three dots) on your username and click **Transfer ownership**.
Within **New company owner**, select the **Company Administrator** you want to transfer the ownership to. Enter your password and click **Transfer ownership**.
Once the transfer is complete, the previous company owner will become a company administrator.
## Delete your company
**Company Owners** can delete a company directly from the dashboard in **Company settings** > **Billing** > **Danger zone**. All projects and services must be removed first. Deleting the company cancels your Sevalla subscription, settles your final balance immediately, and cannot be undone. Refer to [Delete company](/company-settings/delete-company) for the full guide.
# Single Sign-On (SSO) FAQs
Source: https://docs.sevalla.com/company-settings/single-sign-on/faqs
Below, we’ve compiled all the most common SAML SSO questions in one place.
## What is the difference between SAML SSO and OAuth SSO?
SAML SSO and OAuth SSO both allow single sign-on, but they’re built for different use cases, technologies, and types of identities.
SAML SSO is used by businesses and enterprises to provide employees with secure, company-managed access to internal tools. With SAML, you sign in once using your work email and password, and you’re automatically logged in to all approved apps, such as Sevalla, Slack, or Salesforce, without needing to remember separate passwords. Usually, your company’s IT team manages access centrally through the Identity Provider (IdP), deciding who can sign in and which tools they can access. This provides greater security, compliance, and easier management for larger teams.
OAuth SSO, on the other hand, is most common for personal use. It lets you sign in to apps or websites using an existing personal account, such as Google, Apple, or Facebook, instead of creating a new one. This is linked to your personal identity rather than your organization, and the company cannot control who accesses which applications. This means that OAuth SSO is less suitable for enterprise-level access management.
## Can I log in to Sevalla through my Identity Provider (IdP)?
No, you can’t log in to Sevalla directly from your Identity Provider. For security reasons, all logins must start from the Sevalla login page. This ensures that your authentication request is properly verified and prevents potential security issues, such as unauthorized or invalid login attempts. Logging in through Sevalla provides a more secure and reliable sign-in process for your account. For more information about this, refer to IdentityServer's article [The Dangers of SAML IdP-Initiated SSO](https://www.identityserver.com/articles/the-dangers-of-saml-idp-initiated-sso).
## Why can I still log in to Sevalla with my username and password when SSO is mandatory?
Mandatory SSO applies only to the specific company where it has been enabled. If you have access to multiple companies in Sevalla, you can still log in with your username and password. However, you won’t be able to access any company that requires mandatory SSO unless you sign in using that company’s SSO method or your username has been added to the [exceptions list](https://kinsta.com/docs/company-settings/wordpress-saml-sso/#exceptions).
## How long is the session duration?
Your Identity Provider (IdP) determines how long your SSO session remains active and when it expires. If your IdP doesn’t specify a session duration, Sevalla defaults to a 24-hour session.
When your SSO session expires, you’ll be logged out of SSO. If you’re working within a company that uses SSO, you’ll be prompted to reauthenticate. If you have access to multiple companies in Sevalla, you’ll remain logged in overall but will need to reauthenticate before accessing any company that requires SSO.
For details on adjusting session duration, refer to your IdP’s documentation.
## Can I add multiple domains to the SSO configuration?
No, SSO is configured at the company level, and each company can have only one associated domain for SSO.
# Google Workspace SAML SSO
Source: https://docs.sevalla.com/company-settings/single-sign-on/google
Learn how to set up SAML SSO in Sevalla with Google Workspace.
Google Workspace is an Identity Provider (IdP) that enables secure single sign-on (SSO), allowing your company's users to access multiple applications with one login.
With Security Assertion Markup Language (SAML) SSO, employees sign in once using their company credentials (typically email and password). The IdP, such as Google Workspace, verifies their identity and grants seamless, secure access to all connected services, without requiring separate logins for each application.
Company owners or IT administrators can link their organization’s email domain (e.g., @[mycompany.com](http://mycompany.com)) to the IdP so that anyone with a company email address is automatically recognized and can securely sign in to SAML-enabled tools.
Using Sevalla SAML SSO, you can connect Google Workspace to Sevalla by creating a SAML application within Google Workspace, verifying your company’s email domain, and adding the required Google Workspace details in Sevalla. This allows your team to log in with their existing company credentials, eliminating the need to create or manage separate Sevalla accounts.
When using SAML SSO with Sevalla, login must always be initiated from Sevalla. Logging in directly from your Identity Provider (IdP) is not supported.
IdPs only support one active session per browser. If you have multiple Google Workspace accounts and are logged into one, attempting to log into another through Sevalla will result in an error. To switch accounts, log out of Google Workspace or use your browser’s Incognito/Private mode.
## Enable SSO in Sevalla
When you set up SAML SSO, you can navigate away from the SSO setup at any stage to store your progress and return later.
In Sevalla, go to your **Company settings** > **Single sign-on**, and click **Enable**.
Read through the introduction, which explains how SSO will be set up, and click **Continue**.
The next page provides all the information you need to set up your SAML app within Google Workspace.
## Create the app in Google Workspace
In Sevalla, the **Create SAML app** tab provides all the information you need to set up your SAML app within Google Workspace. The following steps explain where to add this information.
When using SAML SSO with Sevalla, all logins must be initiated directly from Sevalla. Logging in from your Identity Provider (IdP) dashboard is not supported. For this reason, you may want to hide the Sevalla app from users’ IdP dashboards to avoid confusion.
Log in to Google Workspace as a user with admin access, open the **Google Apps** menu, and select the **Admin** app.
Select **Web and mobile apps**, and then click **Add app** > **Add custom SAML app**.
In the **App name**, enter the **App name** from Sevalla. You can also download the **App icon** from Sevalla and upload this to the **App Icon**, and add a **Description** if required. Click **Continue**.
## Sevalla setup
In Sevalla, on **Create SAML app**, click **Continue** so that you are on the **Sevalla setup** page. We will return to the **Create SAML app** tab in the next step when adding the service provider details to Google Workspace.
### Email domain
In the **Domain name**, enter the email domain users will use to sign in using SAML SSO, and click **Add domain**.
Only Sevalla accounts with an email address matching the verified domain can authenticate via SAML. For example, if SAML is enabled for `example.com`, only users with an `@example.com` email address will be able to sign in for that company.
Each email address can only be linked to one SAML configuration in Sevalla. This means a domain (e.g., `example.com`) can be associated with only one company at a time. Similarly, each Sevalla user can use SAML authentication for a single company only.
If the domain has already been verified in Sevalla through DNS management or as a site domain, it will automatically be verified. If it hasn’t, you’ll be prompted to add a TXT record to your DNS management service to confirm domain ownership.
Because DNS changes can take time to propagate, you can navigate away from the SSO setup to store your progress and return later.
### Set up Sevalla SAML
In Google Workspace, the **Google Identity Provider details** tab provides all the information you need to set up SAML in Sevalla.
In Sevalla, within the Single sign-on **Sevalla setup** tab, complete the fields as follows:
* **SSO URL:** Copy and paste the **SSO URL** from Google Workspace.
* **Entity ID:** Copy and paste the **Entity ID** from Google Workspace.
* **Public certificate:** Copy and paste the contents of the **Certificate** from Google Workspace.
Click **Back**.
## Add the service provider details in Google Workspace
In Sevalla, within **Single sign-on**, ensure you are on the **Create SAML app** tab.
Within Google Workspace, click **Continue** to the **Service provider details** tab and complete as follows:
* **ACS URL:** Copy and paste the **SSO/ACS URL** from Sevalla.
* **Entity ID:** Copy and paste the **Entity ID** from Sevalla.
* **Start URL:** Copy and paste the **Start URL** from Sevalla.
* **Signed response:** Select this option.
* **Name ID format:** EMAIL.
* **Name ID:** Basic Information > Primary email.
Click **Continue**.
## Map your Google Workspace attributes
Within **Attribute mapping**, you can add the first name, last name, and email to the login credentials. Complete these as follows, and click **ADD MAPPING** after each entry:
| **Google directory attributes** | **App attributes** |
| ------------------------------- | ------------------ |
| Fiest name | firstName |
| Last name | lastName |
| Primary email | email |
Click **Finish**.
## Set up user access to the Google Workspace app
In Google Workspace, in the Admin app, go to **Apps** > **Web and mobile apps**, select the Sevalla application, and click **User access**.
Select the **Group(s)** or **Organisational unit(s)** you want to grant access to Sevalla via SAML. Then select **ON** or **ON for everyone** and click **SAVE**. For more information about Groups and Organisational units, refer to [Google Workspace Admin Help](https://support.google.com/a?sjid=10187148707879574500-EU#topic=4388346).
To test authentication, make sure the Sevalla user account you’re signed in with is assigned.
## Test the authentication in Sevalla
You cannot enable SAML SSO within Sevalla without first testing the authentication.
In Sevalla, within Single sign-on, click **Continue** until you are on the **Test and finish** tab, and click **Test authentication**.
A notification appears if the test was successful or if the test fails.
If the test fails, click **Back** and check your SAML settings within your IdP and within Sevalla.
If the test is successful and you want to enable SAML, click **Save and set SSO live**.
Your Sevalla company users will now be able to sign in with SAML SSO or by entering their username and password. Users who sign in through an IdP are not required to complete Sevalla's 2FA, as authentication is handled directly by the IdP.
If you want to force users to sign on via SAML, you can enable Mandatory SSO and add Exceptions. You can also enable JIT provisioning to allow users authorized by your IdP to access your Sevalla company without requiring an invitation.
## Change the session duration
Your Identity Provider (IdP) determines how long your SSO session remains active and when it expires. If your IdP doesn’t specify a session duration, Sevalla defaults to a 24-hour session.
When your SSO session expires, you’ll be logged out of SSO. If you’re working within a company that uses SSO, you’ll be prompted to reauthenticate. If you have access to multiple companies in Sevalla, you’ll remain logged in overall but will need to reauthenticate before accessing any company that requires SSO.
For details on adjusting session duration, refer to the [Google Workspace Admin Help](https://support.google.com/a/answer/7576830?sjid=15638353417037270933-EU).
# Microsoft Entra SAML SSO
Source: https://docs.sevalla.com/company-settings/single-sign-on/microsoft
Learn how to set up SAML SSO in Sevalla with Microsoft Entra.
[Microsoft Entra](https://entra.microsoft.com/) (formerly Azure) is an Identity Provider (IdP) that enables secure single sign-on (SSO), allowing your company's users to access multiple applications with one login.
With Security Assertion Markup Language (SAML) SSO, employees sign in once using their company credentials (typically email and password). The IdP, such as Microsoft Entra, verifies their identity and grants seamless, secure access to all connected services, without requiring separate logins for each application.
Company owners or IT administrators can link their organization’s email domain (e.g., @[mycompany.com](http://mycompany.com)) to the IdP so that anyone with a company email address is automatically recognized and can securely sign in to SAML-enabled tools.
Using Sevalla SAML SSO, you can connect Microsoft Entra to Sevalla by creating a SAML application within Microsoft Entra, verifying your company’s email domain, and adding the required Microsoft Entra details in Sevalla. This allows your team to log in with their existing company credentials, eliminating the need to create or manage separate Sevalla accounts.
When using SAML SSO with Sevalla, login must always be initiated from Sevalla. Logging in directly from your Identity Provider (IdP) is not supported.
IdPs only support one active session per browser. If you have multiple Google Workspace accounts and are logged into one, attempting to log into another through Sevalla will result in an error. To switch accounts, log out of Google Workspace or use your browser’s Incognito/Private mode.
## Enable SSO in Sevalla
When you set up SAML SSO, you can navigate away from the SSO setup at any stage to store your progress and return later.
In Sevalla, go to your **Company settings** > **Single sign-on**, and click **Enable**.
Read through the introduction, which explains how SSO will be set up, and click **Continue**.
The next page provides all the information you need to set up your SAML app within Microsoft Entra.
## Set up the app integration in Microsoft Entra
In Sevalla, the **Create SAML app** tab provides all the information you need to set up your SAML app within Microsoft Entra. The following steps explain where to add this information.
When using SAML SSO with Sevalla, all logins must be initiated directly from Sevalla. Logging in from your Identity Provider (IdP) dashboard is not supported. For this reason, you may want to hide the Sevalla app from users’ IdP dashboards to avoid confusion.
Log in to Microsoft Entra as a user with admin access, and within the Microsoft Entra admin center, click **Entra ID** > **Enterprise applications** > **New application**.
Click **Create your own application**, enter a name for your application, for example, Sevalla Dashboard, and click **Create**.
Once the application is created, click **Single sign-on** and select **SAML**.
Within **Basic SAML Configuration**, click **Edit**.
Complete the **Basic SAML Configuration** in Microsoft Entra as follows:
* **Identifier (Entity ID):** Click **Add identifier** and then copy and paste the **Entity ID** from Sevalla.
* **Reply URL (Assertion Consumer Service URL):** Click **Add reply URL** and then copy and paste the **SSO/ACS URL** from Sevalla.
* **Sign on URL:** Copy and paste the **Start URL** from Sevalla.
Leave all other fields as default and click **Save**.
## Map your Microsoft Entra attributes
Within Microsoft Entra, you must map the firstName, lastName, and email attributes from Sevalla to the correct fields within Microsoft Entra. For more information about how to do this, refer to the [Microsoft Entra documentation](https://learn.microsoft.com/en-us/entra/identity-platform/saml-claims-customization).
## Assign users to the Microsoft Entra app
In Microsoft Entra, go to **Enterprise apps**, select the application you set up for the Sevalla Dashboard, click **Users and groups**, and then click **Add user/group**.
Click **None selected**, select the users or groups you want to grant Sevalla access via SSO, and then click **Select**.
Click **Assign** and then click **Assign to People**. If you have your users set up in groups, click **Assign to Groups**. Click **Assign** on each user or group you want to assign to the Sevalla SAML SSO application and then click **Done**.
To test authentication, make sure the Sevalla user account you’re signed in with is assigned.
## Sevalla setup
In Sevalla, on **Create SAML app**, click **Continue** so that you are on the **Sevalla setup** page.
### Email domain
In the **Domain name**, enter the email domain users will use to sign in using SAML SSO, and click **Add domain**.
Only Sevalla accounts with an email address matching the verified domain can authenticate via SAML. For example, if SAML is enabled for `example.com`, only users with an `@example.com` email address will be able to sign in for that company.
Each email address can only be linked to one SAML configuration in Sevalla. This means a domain (e.g., `example.com`) can be associated with only one company at a time. Similarly, each Sevalla user can use SAML authentication for a single company only.
If the domain has already been verified in Sevalla through DNS management or as a site domain, it will automatically be verified. If it hasn’t, you’ll be prompted to add a TXT record to your DNS management service to confirm domain ownership.
Because DNS changes can take time to propagate, you can navigate away from the SSO setup to store your progress and return later.
#### Set up Sevalla SAML
In Microsoft Entra, go to **Enterprise apps**, select the application you set up for the Sevalla Dashboard, and click **Single sign-on**.
In Sevalla, within the Single sign-on **Sevalla setup** tab, complete the fields as follows:
* **SSO URL:** Copy and paste the **Login URL** from the **Set up Sevalla Dashboard** section in Microsoft Entra.
* **Entity ID:** Copy and paste the **Microsoft Entra Identifier** from the **Set up Sevalla Dashboard** section in Microsoft Entra.
* **Public certificate:** In Microsoft Entra, within **SAML Certificates**, click **Download** on **Certificate (Base64)**. Open this file in any text editor, and copy and paste the contents into Sevalla.
Certificates can expire, so you may need to update this in the future. Company Owners and Company Administrators will receive a notification three weeks prior to certificate expiration to ensure the certificate is updated in a timely manner.
Click **Continue**.
## Test the authentication in Sevalla
You cannot enable SAML SSO within Sevalla without first testing the authentication.
In Sevalla, within Single sign-on, click **Continue** until you are on the **Test and finish** tab, and click **Test authentication**.
A notification appears if the test was successful or if the test fails.
If the test fails, click **Back** and check your SAML settings within your IdP and within Sevalla.
If the test is successful and you want to enable SAML, click **Save and set SSO live**.
Your Sevalla company users will now be able to sign in with SAML SSO or by entering their username and password. Users who sign in through an IdP are not required to complete Sevalla's 2FA, as authentication is handled directly by the IdP.
If you want to force users to sign on via SAML, you can enable Mandatory SSO and add Exceptions. You can also enable JIT provisioning to allow users authorized by your IdP to access your Sevalla company without requiring an invitation.
## Change the session duration
Your Identity Provider (IdP) determines how long your SSO session remains active and when it expires. If your IdP doesn’t specify a session duration, Sevalla defaults to a 24-hour session.
When your SSO session expires, you’ll be logged out of SSO. If you’re working within a company that uses SSO, you’ll be prompted to reauthenticate. If you have access to multiple companies in Sevalla, you’ll remain logged in overall but will need to reauthenticate before accessing any company that requires SSO.
For details on adjusting session duration, refer to the [Microsoft Entra Documentation](https://learn.microsoft.com/en-us/entra/identity/conditional-access/howto-conditional-access-session-lifetime).
# Okta SAML SSO
Source: https://docs.sevalla.com/company-settings/single-sign-on/okta
Learn how to set up SAML SSO in Sevalla with Okta.
[Okta](https://www.okta.com/) is an Identity Provider (IdP) that enables secure single sign-on (SSO), allowing your company's users to access multiple applications with one login.
With Security Assertion Markup Language (SAML) SSO, employees sign in once using their company credentials (typically email and password). The IdP, such as Okta, verifies their identity and grants seamless, secure access to all connected services, without requiring separate logins for each application.
Company owners or IT administrators can link their organization’s email domain (e.g., @[mycompany.com](http://mycompany.com)) to the IdP so that anyone with a company email address is automatically recognized and can securely sign in to SAML-enabled tools.
Using Sevalla SAML SSO, you can connect Okta to Sevalla by creating a SAML application within Okta, verifying your company’s email domain, and adding the required Okta details in Sevalla. This allows your team to log in with their existing company credentials, eliminating the need to create or manage separate Sevalla accounts.
When using SAML SSO with Sevalla, login must always be initiated from Sevalla. Logging in directly from your Identity Provider (IdP) is not supported.
IdPs only support one active session per browser. If you have multiple Google Workspace accounts and are logged into one, attempting to log into another through Sevalla will result in an error. To switch accounts, log out of Google Workspace or use your browser’s Incognito/Private mode.
## Enable SSO in Sevalla
When you set up SAML SSO, you can navigate away from the SSO setup at any stage to store your progress and return later.
In Sevalla, go to your **Company settings** > **Single sign-on**, and click **Enable**.
Read through the introduction, which explains how SSO will be set up, and click **Continue**.
The next page provides all the information you need to set up your SAML app within Okta.
## Set up the app integration in Okta
In Sevalla, the **Create SAML app** tab provides all the information you need to set up your SAML app within Okta. The following steps explain where to add this information.
When using SAML SSO with Sevalla, all logins must be initiated directly from Sevalla. Logging in from your Identity Provider (IdP) dashboard is not supported. For this reason, you may want to hide the Sevalla app from users’ IdP dashboards to avoid confusion.
Log in to Okta as a user with admin access, and within the Admin Dashboard, click **Applications** > **Create App Integration**.
Select **SAML 2.0** as the sign-in method and click **Next**.
Enter the **App name** from Sevalla. You can also download the **App icon** from Sevalla and upload this to the **App logo**, if required. Click **Next**.
Complete the **Configure SAML** in Okta as follows:
* **Single sign-on URL:** Copy and paste the **SSO/ACS URL** from Sevalla.
* **Audience URI (SP Entity ID):** Copy and paste the **Entity ID** from Sevalla.
* **Name ID format:** EmailAddress
* **Application username:** Email
* **Update application username on:** Create and update
Leave all other fields as default and click **Next**.
On the **Feedback** tab, select **This is an internal app that we have created** and then click **Finish**.
You now need to set up the SAML app within Sevalla.
## Map your Okta attributes
Within Okta, you must map the firstName, lastName, and email attributes from Sevalla to the correct fields within Okta. For more information about how to do this, refer to the [Okta docs](https://help.okta.com/en-us/content/topics/users-groups-profiles/usgp-map-attributes.htm).
## Assign users to the Okta app
In Okta, go to **Applications**, select the application you set up for the Sevalla Dashboard, and click **Assignments**.
Click **Assign** and then click **Assign to People**. If you have your users set up in groups, click **Assign to Groups**. Click **Assign** on each user or group you want to assign to the Sevalla SAML SSO application and then click **Done**.
To test authentication, make sure the Sevalla user account you’re signed in with is assigned.
## Sevalla setup
In Sevalla, on **Create SAML app**, click **Continue** so that you are on the **Sevalla setup** page.
### Email domain
In the **Domain name**, enter the email domain users will use to sign in using SAML SSO, and click **Add domain**.
Only Sevalla accounts with an email address matching the verified domain can authenticate via SAML. For example, if SAML is enabled for `example.com`, only users with an `@example.com` email address will be able to sign in for that company.
Each email address can only be linked to one SAML configuration in Sevalla. This means a domain (e.g., `example.com`) can be associated with only one company at a time. Similarly, each Sevalla user can use SAML authentication for a single company only.
If the domain has already been verified in Sevalla through DNS management or as a site domain, it will automatically be verified. If it hasn’t, you’ll be prompted to add a TXT record to your DNS management service to confirm domain ownership.
Because DNS changes can take time to propagate, you can navigate away from the SSO setup to store your progress and return later.
#### Set up Sevalla SAML
In Okta, go to **Applications**, select the application you set up for the Sevalla Dashboard, click **Sign On**, and then click**View SAML setup instructions** .
This page provides all the information you need to set up SAML in Sevalla.
In Sevalla, within the Single sign-on **Sevalla setup** tab, complete the fields as follows:
* **SSO URL:** Copy and paste the **Identity Provider Single Sign-On URL** from Okta.
* **Entity ID:** Copy and paste the **Identity Provider Issuer** from Okta.
* **Public certificate:** Copy and paste the **X.509 Certificate** from Okta.
Certificates can expire, so you may need to update this in the future. Company Owners and Company Administrators will receive a notification three weeks prior to certificate expiration to ensure the certificate is updated in a timely manner.
Click **Continue**.
## Test the authentication in Sevalla
You cannot enable SAML SSO within Sevalla without first testing the authentication.
In Sevalla, within Single sign-on, click **Continue** until you are on the **Test and finish** tab, and click **Test authentication**.
A notification appears if the test was successful or if the test fails.
If the test fails, click **Back** and check your SAML settings within your IdP and within Sevalla.
If the test is successful and you want to enable SAML, click **Save and set SSO live**.
Your Sevalla company users will now be able to sign in with SAML SSO or by entering their username and password. Users who sign in through an IdP are not required to complete Sevalla's 2FA, as authentication is handled directly by the IdP.
If you want to force users to sign on via SAML, you can enable Mandatory SSO and add Exceptions. You can also enable JIT provisioning to allow users authorized by your IdP to access your Sevalla company without requiring an invitation.
## Change the session duration
Your Identity Provider (IdP) determines how long your SSO session remains active and when it expires. If your IdP doesn’t specify a session duration, Sevalla defaults to a 24-hour session.
When your SSO session expires, you’ll be logged out of SSO. If you’re working within a company that uses SSO, you’ll be prompted to reauthenticate. If you have access to multiple companies in Sevalla, you’ll remain logged in overall but will need to reauthenticate before accessing any company that requires SSO.
For details on adjusting session duration, refer to the [Okta Help Center](https://support.okta.com/help/s/article/How-to-Adjust-Session-Lifetime-and-Idle-Value-for-Users?language=en_US).
# OneLogin SAML SSO
Source: https://docs.sevalla.com/company-settings/single-sign-on/onelogin
Learn how to set up SAML SSO in Sevalla with OneLogin.
[OneLogin](https://www.onelogin.com/) is an Identity Provider (IdP) that enables secure single sign-on (SSO), allowing your company's users to access multiple applications with one login.
With Security Assertion Markup Language (SAML) SSO, employees sign in once using their company credentials (typically email and password). The IdP, such as OneLogin, verifies their identity and grants seamless, secure access to all connected services, without requiring separate logins for each application.
Company owners or IT administrators can link their organization’s email domain (e.g., @[mycompany.com](http://mycompany.com)) to the IdP so that anyone with a company email address is automatically recognized and can securely sign in to SAML-enabled tools.
Using Sevalla SAML SSO, you can connect OneLogin to Sevalla by creating a SAML application within OneLogin, verifying your company’s email domain, and adding the required OneLogin details in Sevalla. This allows your team to log in with their existing company credentials, eliminating the need to create or manage separate Sevalla accounts.
When using SAML SSO with Sevalla, login must always be initiated from Sevalla. Logging in directly from your Identity Provider (IdP) is not supported.
IdPs only support one active session per browser. If you have multiple Google Workspace accounts and are logged into one, attempting to log into another through Sevalla will result in an error. To switch accounts, log out of Google Workspace or use your browser’s Incognito/Private mode.
## Enable SSO in Sevalla
When you set up SAML SSO, you can navigate away from the SSO setup at any stage to store your progress and return later.
In Sevalla, go to your **Company settings** > **Single sign-on**, and click **Enable**.
Read through the introduction, which explains how SSO will be set up, and click **Continue**.
The next page provides all the information you need to set up your SAML app within OneLogin.
## Set up the app integration in OneLogin
In Sevalla, the **Create SAML app** tab provides all the information you need to set up your SAML app within OneLogin. The following steps explain where to add this information.
When using SAML SSO with Sevalla, all logins must be initiated directly from Sevalla. Logging in from your Identity Provider (IdP) dashboard is not supported. For this reason, you may want to hide the Sevalla app from users’ IdP dashboards to avoid confusion.
Log in to OneLogin as a user with admin access, and within **Administration**, click **Applications** > **Applications** > **Add App**.
Search for 'saml custom connector' and select **SAML Custom Connector (Advanced)**.
In the Display Name, enter the **App name** from Sevalla. You can also download the **App icon** from Sevalla and upload this to the **Square Icon**, and add a **Description** if required. Click **Save**.
Click **Configuration** and complete as follows:
* **Audience (EntityID):** Copy and paste the **Entity ID** from Sevalla.
* **Recipient:** Copy and paste the **SSO/ACS URL** from Sevalla.
* **ACS (Consumer) URL Validator:** Copy and paste the **SSO/ACS URL** from Sevalla.
* **ACS (Consumer) URL:** Copy and paste the **SSO/ACS URL** from Sevalla.
* **Login URL:** Copy and paste the **Start URL** from Sevalla.
* **SAML initiator:** Select **Service Provider**.
* **SAML nameID format:** Select **Email**.
* **SAML issuer type:** Select **Specific**.
* **SAML signature element:** Select **Assertion**.
* **Sign SLO Response:** Select this option.
* **Sign SLO Request:** Select this option.
Leave all other fields as default and click **Save**.
Click **SSO**, and within **SAML Signature Algorithm** select **SHA-256**, and click **Save**.
## Map your OneLogin attributes
Within OneLogin, you must map the firstName, lastName, and email attributes from Sevalla to the correct fields within OneLogin. For more information about how to do this, refer to the [OneLogin documentation](https://onelogin.service-now.com/support?id=kb_article\&sys_id=c1e4255a9758ea900f94b86ef053af1a\&kb_category=566ffd6887332910695f0f66cebb3556).
## Assign users to the OneLogin app
In OneLogin, you can assign a policy to the application to allow all users using the policy to log in to the app. Go to **Applications** > **Applications**, select the application you set up for the Sevalla Dashboard, click **Access**, choose the policy you want to assign, and click **Save**. For more information about security policies, refer to [OneLogin's documentation](https://onelogin.service-now.com/support?id=kb_article\&sys_id=1510ecd787dee610f7b8a7dd3fbb35d9\&kb_category=95c6573887772910763a0ed7dabb3538).
You can also assign individual users to the application. In OneLogin, click **Users** > **Users**, select the user you want to assign, click **Applications**, and click the plus icon.
From the **Select application** dropdown, select the Sevalla application, and click **Continue**.
Select **Allow the user to sign in**, ensure the credentials are correct, and click **Save**.
To test authentication, make sure the Sevalla user account you’re signed in with is assigned.
## Sevalla setup
In Sevalla, on **Create SAML app**, click **Continue** so that you are on the **Sevalla setup** page.
### Email domain
In the **Domain name**, enter the email domain users will use to sign in using SAML SSO, and click **Add domain**.
Only Sevalla accounts with an email address matching the verified domain can authenticate via SAML. For example, if SAML is enabled for `example.com`, only users with an `@example.com` email address will be able to sign in for that company.
Each email address can only be linked to one SAML configuration in Sevalla. This means a domain (e.g., `example.com`) can be associated with only one company at a time. Similarly, each Sevalla user can use SAML authentication for a single company only.
If the domain has already been verified in Sevalla through DNS management or as a site domain, it will automatically be verified. If it hasn’t, you’ll be prompted to add a TXT record to your DNS management service to confirm domain ownership.
Because DNS changes can take time to propagate, you can navigate away from the SSO setup to store your progress and return later.
#### Set up Sevalla SAML
In OneLogin, go to **Applications** > **Applications**, select the application you set up for the Sevalla Dashboard, and click **SSO**.
This page provides all the information you need to set up SAML in Sevalla.
In Sevalla, within the Single sign-on **Sevalla setup** tab, complete the fields as follows:
* **SSO URL:** Copy and paste the **SAML 2.0 Endpoint (HTTP)** from OneLogin.
* **Entity ID:** Copy and paste the **Issuer URL** from OneLogin.
* **Public certificate:** In OneLogin, on the **X.509 Certificate**, click **View Details**, copy and paste the contents of the **X.509 Certificate**.
Certificates can expire, so you may need to update this in the future. Company Owners and Company Administrators will receive a notification three weeks prior to certificate expiration to ensure the certificate is updated in a timely manner.
Click **Continue**.
## Test the authentication in Sevalla
You cannot enable SAML SSO within Sevalla without first testing the authentication.
In Sevalla, within Single sign-on, click **Continue** until you are on the **Test and finish** tab, and click **Test authentication**.
A notification appears if the test was successful or if the test fails.
If the test fails, click **Back** and check your SAML settings within your IdP and within Sevalla.
If the test is successful and you want to enable SAML, click **Save and set SSO live**.
Your Sevalla company users will now be able to sign in with SAML SSO or by entering their username and password. Users who sign in through an IdP are not required to complete Sevalla's 2FA, as authentication is handled directly by the IdP.
If you want to force users to sign on via SAML, you can enable Mandatory SSO and add Exceptions. You can also enable JIT provisioning to allow users authorized by your IdP to access your Sevalla company without requiring an invitation.
## Change the session duration
Your Identity Provider (IdP) determines how long your SSO session remains active and when it expires. If your IdP doesn’t specify a session duration, Sevalla defaults to a 24-hour session.
When your SSO session expires, you’ll be logged out of SSO. If you’re working within a company that uses SSO, you’ll be prompted to reauthenticate. If you have access to multiple companies in Sevalla, you’ll remain logged in overall but will need to reauthenticate before accessing any company that requires SSO.
For details on adjusting session duration, refer to the [OneLogin Knowledge Base](https://support.onelogin.com/kb/4271392/user-policies).
# Single Sign-On (SSO) Overview
Source: https://docs.sevalla.com/company-settings/single-sign-on/overview
Find out how to set up SAML SSO with Sevalla.
Security Assertion Markup Language (SAML) Single Sign-On (SSO) allows users to securely access multiple applications using a single set of credentials, typically their company email and password. Instead of creating separate logins for each service, users authenticate once through a company-managed Identity Provider (IdP) such as Okta, OneLogin, Microsoft Entra, or Google Workspace.
The IdP verifies the user’s identity and grants access to all connected applications without requiring additional logins. The organization centrally manages access control, authentication policies, and permissions, providing greater security, compliance, and administrative efficiency.
With SAML SSO, company owners or IT administrators can link their corporate email domain (e.g., `@mycompany.com`) to the organization’s IdP. This ensures that anyone with a company email address is automatically recognized and securely authenticated when accessing approved tools and services.
At Sevalla, SAML SSO lets you connect your company’s IdP directly to Sevalla. By creating a SAML application in your IdP and adding the connection details to Sevalla, your team can sign in using their existing company credentials, eliminating the need to create or manage separate Sevalla passwords. This also gives company owners centralized control over who can access Sevalla, directly through the IdP.
Sevalla supports all identity providers (IdPs) that use the SAML standard, including Microsoft Entra ID, Okta, OneLogin, Google Workspace, Auth0, Duo, JumpCloud, and more.
When using SAML SSO with Sevalla, login must always be initiated from Sevalla. Logging in directly from your Identity Provider (IdP) is not supported.
IdPs only support one active session per browser. If you have multiple accounts and are logged into one, attempting to log into another through Sevalla will result in an error. To switch accounts, log out of your IdP or use your browser’s Incognito/Private mode.
## Set up SAML SSO
For detailed step-by-step guides for the most popular IdPs, refer to one of the following:
* [Google Workspace SAML SSO](https://docs.sevalla.com/company-settings/single-sign-on/google)
* [Microsoft Entra SAML SSO](https://docs.sevalla.com/company-settings/single-sign-on/microsoft)
* [Okta SAML SSO](https://docs.sevalla.com/company-settings/single-sign-on/okta)
* [OneLogin SAML SSO](https://docs.sevalla.com/company-settings/single-sign-on/onelogin)
* [Ping Identity SAML SSO](https://docs.sevalla.com/company-settings/single-sign-on/ping)
### Enable SSO in Sevalla
When you set up SAML SSO, you can navigate away from the SSO setup at any stage to store your progress and return later.
In Sevalla, go to your **Company settings** > **Single sign-on**, and click **Enable**.
Read through the introduction, which explains how SSO will be set up, and click **Continue**.
### Set up the app integration in your IdP
Use the information provided within **Create SAML app** to set up a SAML app within your identity provider, and then click **Continue**.
* **App name:** Copy and paste this into the Application Name field in your IdP.
* **App description:** Copy and paste this into the Application Description field in your IdP. This field is typically optional.
* **App icon:** Click Download to get the Sevalla icon, then upload it to your IdP application.
* **SSO/ACS URL:** This is the Sevalla endpoint your IdP redirects to after authentication. It processes the SAML response, verifies it, and establishes the user’s session in Sevalla. Copy and paste this into the **SSO**/**ACS**/**Recipient**/**Single sign-on URL** field in your IdP.
* **Entity ID:** Sevalla's unique identifier within your IdP, used to recognize Sevalla as the service provider. Copy and paste this into the **Entity ID**/**Audience URI**/**Audience** field in your IdP.
* **Start URL:** The web address for Sevalla's SSO access portal. This is the entry point users visit to log in using SSO, triggering the SAML authentication request to the IdP. Copy and paste this into the **Start URL**/**Login URL** field in your IdP.
* **Signed Response:** A signed response provides secure digital verification, allowing Sevalla to confirm a user’s identity and grant access without requiring an additional login.
* **Name ID format:** Defines how Sevalla identifies users. This must be set to an email address format in the IdP.
* **Required attributes:** The attributes Sevalla requires from your IdP to complete the login process.
As Sevalla is a [**Kinsta**](https://kinsta.com/) product, we use `my.kinsta.com` in the **SSO/ACS URL**, **Entity ID**, and **Start URL.** This is a normal part of the Sevalla experience.
### Sevalla setup
#### Email domain
In the **Domain name**, enter the email domain users will use to sign in using SAML SSO, and click **Add domain**.
Only Sevalla accounts with an email address matching the verified domain can authenticate via SAML. For example, if SAML is enabled for `example.com`, only users with an `@example.com` email address will be able to sign in for that company.
Each email address can only be linked to one SAML configuration in Sevalla. This means a domain (e.g., `example.com`) can be associated with only one company at a time. Similarly, each Sevalla user can use SAML authentication for a single company only.
If the domain has already been verified in Sevalla through DNS management or as a site domain, it will automatically be verified. If it hasn’t, you’ll be prompted to add a TXT record to your DNS management service to confirm domain ownership.
Because DNS changes can take time to propagate, you can navigate away from the SSO setup to store your progress and return later.
#### Set up Sevalla SAML
When the domain has been verified, use the information provided from your IdP to complete the **SSO URL**, **Entity ID**, and **Public certificate**, and then click **Continue**.
Certificates can expire, so you may need to update this in the future. Company Owners and Company Administrators will receive a notification three weeks prior to certificate expiration to ensure the certificate is updated in a timely manner.
### Test the authentication in Sevalla
To check everything is set up correctly, click **Test authentication**.
A notification appears if the test was successful or if the test fails.
If the test fails, click **Back** and check your SAML settings within your IdP and within Sevalla.
If the test is successful and you want to enable SAML, click **Save and set SSO live**.
Your Sevalla company users will now be able to sign in with SAML SSO or by entering their username and password. If you want to force users to sign on via SAML, you can enable Mandatory SSO. Users who sign in through an IdP are not required to complete Sevalla's 2FA, as authentication is handled directly by the IdP.
## Mandatory single sign-on
To require all users to log in with SSO, enable mandatory SSO. With this setting, all users are prompted to sign in via the identity provider (IdP) rather than their Sevalla credentials. If a user has already authenticated with SAML elsewhere, they'll automatically be logged in. If a user switches companies to a company that does not have SSO enabled, they must enter their Sevalla credentials.
You can also add Exceptions to allow specific users to log in with a password even when mandatory SSO is enabled. This is useful for 3rd parties that need to access your company but don't have an email address in your domain, such as developers.
We strongly recommend adding at least one user as an exception, such as the company owner, so you can still access your company with your Sevalla credentials if any issues occur with SAML SSO.
If mandatory SSO is enabled but SAML is **not** enabled, users will be required to log in with their Sevalla credentials.
## Exceptions
If mandatory SSO is enabled, you can add specific users to an exceptions list, allowing them to log in with their Sevalla credentials instead of SSO. This is useful for 3rd parties that need to access your company but don't have an email address in your domain, such as developers.
We strongly recommend adding at least one user as an exception, such as the company owner, so you can still access your company with your Sevalla credentials if any issues occur with SAML SSO.
### Add a user to exceptions
To add a user to the exceptions list, click **Add exception**. Select the user from the list and click **Add**.
### Remove a user from exceptions
To remove a user from the exceptions list, click the trash can icon next to the user, then click **Continue**.
When you remove the last user from the exceptions list, a warning message will appear. If all users are removed and an issue occurs with the IdP, you may lose access to your Sevalla company.
## Just-in-time provisioning
Just-in-time (JIT) provisioning allows users authorized by your IdP to access your Sevalla company without requiring an invitation. In most cases, this means anyone with an email address on your domain. When a user signs in to Sevalla, they are directed through IdP SSO and do not need to create a separate Sevalla account. By default, users provisioned through JIT are assigned the **Company Developer** role. You can adjust each user’s access level after they join, or update the default role to define the access level new JIT-provisioned users receive upon joining.
### Change default role
When JIT provisioning is enabled, users are assigned the **Company Developer** by default. To change their default access level, click **Change default role**.
You can then choose the access level you want to assign to users who join via JIT provisioning, and click **Save changes**.
### Enable JIT provisioning
Once you have set the default role, to enable JIT provisioning, click **Enable**, and then click **Continue**.
### Disable JIT provisioning
To disable JIT provisioning, click **Disable**, and then click **Continue**. If you disable JIT provisioning and SSO, users created through JIT will be prompted to set a password the next time they log in to Sevalla.
## Removing users
To fully revoke access, users must be removed from both Sevalla and your identity provider (IdP).
* If SSO and JIT provisioning are enabled, removing a user from Sevalla alone will not block access. The user can still sign in through your IdP.
* If you remove a user only from your IdP and mandatory SSO is not enabled, the user can still log in with their Sevalla credentials.
## Change the session duration
Your identity provider (IdP) controls the duration and expiration of your SSO session. Refer to your IdP's supporting documentation for information about how to change this.
## Disable SSO
If you disable SSO, users will no longer be able to sign in using SAML SSO and must instead log in with their email address and password.
If JIT provisioning was previously enabled, some users may not have an existing Sevalla password. In this case, they can create one by selecting **Forgot password** on the Sevalla login page.
Once SSO is disabled, all users will be required to use Sevalla's Two-Factor Authentication (2FA).
For security, multiple failed login attempts may lock the account. If this happens, Sevalla will send an email containing a temporary login link so the user can regain access to Sevalla.
To disable SSO, within **Single sign-on**, click **Disable**.
## What is the difference between SAML SSO and OAuth SSO?
SAML SSO and OAuth SSO both allow single sign-on, but they’re built for different use cases, technologies, and types of identities.
SAML SSO is used by businesses and enterprises to provide employees with secure, company-managed access to internal tools. With SAML, you sign in once using your work email and password, and you’re automatically logged in to all approved apps, such as Sevalla, Slack, or Salesforce, without needing to remember separate passwords. Usually, your company’s IT team manages access centrally through the Identity Provider (IdP), deciding who can sign in and which tools they can access. This provides greater security, compliance, and easier management for larger teams.
OAuth SSO, on the other hand, is most common for personal use. It lets you sign in to apps or websites using an existing personal account, such as Google, Apple, or Facebook, instead of creating a new one. This is linked to your personal identity rather than your organization, and the company cannot control who accesses which applications. This means that OAuth SSO is less suitable for enterprise-level access management.
# Ping Identity SAML SSO
Source: https://docs.sevalla.com/company-settings/single-sign-on/ping
Learn how to set up SAML SSO in Sevalla with Ping Identity.
[Ping Identity](https://www.pingidentity.com/en.html) is an Identity Provider (IdP) that enables secure single sign-on (SSO), allowing your company's users to access multiple applications with one login.
With Security Assertion Markup Language (SAML) SSO, employees sign in once using their company credentials (typically email and password). The IdP, such as Ping Identity, verifies their identity and grants seamless, secure access to all connected services, without requiring separate logins for each application.
Company owners or IT administrators can link their organization’s email domain (e.g., @[mycompany.com](http://mycompany.com)) to the IdP so that anyone with a company email address is automatically recognized and can securely sign in to SAML-enabled tools.
Using Sevalla SAML SSO, you can connect Ping Identity to Sevalla by creating a SAML application within Ping Identity, verifying your company’s email domain, and adding the required Ping Identity details in Sevalla. This allows your team to log in with their existing company credentials, eliminating the need to create or manage separate Sevalla accounts.
When using SAML SSO with Sevalla, login must always be initiated from Sevalla. Logging in directly from your Identity Provider (IdP) is not supported.
IdPs only support one active session per browser. If you have multiple Google Workspace accounts and are logged into one, attempting to log into another through Sevalla will result in an error. To switch accounts, log out of Google Workspace or use your browser’s Incognito/Private mode.
## Enable SSO in Sevalla
When you set up SAML SSO, you can navigate away from the SSO setup at any stage to store your progress and return later.
In Sevalla, go to your **Company settings** > **Single sign-on**, and click **Enable**.
Read through the introduction, which explains how SSO will be set up, and click **Continue**.
The next page provides all the information you need to set up your SAML app within Ping Identity.
## Set up the app integration in Ping Identity
In Sevalla, the **Create SAML app** tab provides all the information you need to set up your SAML app within Ping Identity. The following steps explain where to add this information.
When using SAML SSO with Sevalla, all logins must be initiated directly from Sevalla. Logging in from your Identity Provider (IdP) dashboard is not supported. For this reason, you may want to hide the Sevalla app from users’ IdP dashboards to avoid confusion.
Log in to Ping Identity as a user with admin access, and within **Environments**, click **Create Environment**.
Click **Create a Workforce Solution** and then click **Manage Environment**.
Click **Applications** and then click the plus sign to add a new application.
Enter the **Application name** from Sevalla. You can also download the **App icon** from Sevalla and upload it to the **Icon**, if required. Select **SAML Application** and click **Configure**.
Select **Manually Enter** and complete the **SAML Configuration** in Ping Identity as follows:
* **ACS URLs:** Copy and paste the **SSO/ACS URL** from Sevalla.
* **Entity ID:** Copy and paste the **Entity ID** from Sevalla.
Click **Save**.
## Map your Ping Identity attributes
Click **Attribute Mappings** and then click the edit icon.
Add the following attributes:
| **Attributes** | **PingOne Mappings** | **Required** |
| -------------- | -------------------- | ------------ |
| firstName | Given Name | Selected |
| lastName | Family Name | Selected |
| email | Email Address | Selected |
Click **Save**.
## Assign user access in Ping Identity
By default, the new application will allow all users to access it. To define specific user groups for access to this, in Ping Identity, navigate to **Applications**, select the application you set up for the Sevalla Dashboard, click **Access**, and then click the edit icon. You can choose whether you want only admin users to access the application or select which groups should have access.
## Sevalla setup
In Sevalla, on **Create SAML app**, click **Continue** so that you are on the **Sevalla setup** page.
### Email domain
In the **Domain name**, enter the email domain users will use to sign in using SAML SSO, and click **Add domain**.
Only Sevalla accounts with an email address matching the verified domain can authenticate via SAML. For example, if SAML is enabled for `example.com`, only users with an `@example.com` email address will be able to sign in for that company.
Each email address can only be linked to one SAML configuration in Sevalla. This means a domain (e.g., `example.com`) can be associated with only one company at a time. Similarly, each Sevalla user can use SAML authentication for a single company only.
If the domain has already been verified in Sevalla through DNS management or as a site domain, it will automatically be verified. If it hasn’t, you’ll be prompted to add a TXT record to your DNS management service to confirm domain ownership.
Because DNS changes can take time to propagate, you can navigate away from the SSO setup to store your progress and return later.
#### Set up Sevalla SAML
In Ping Identity, go to **Applications**, select the application you set up for the Sevalla Dashboard, click **Overview**, and then scroll down to **Connection Details**.
This page provides all the information you need to set up SAML in Sevalla.
In Sevalla, within the Single sign-on **Sevalla setup** tab, complete the fields as follows:
* **SSO URL:** Copy and paste the **Initiate Single Sign-On URL** from Ping Identity.
* **Entity ID:** Copy and paste the **Issuer ID** from Ping Identity.
* **Public certificate:** Within Ping Identity, click **Download Signing Certificate**, select **X509 PEM (.crt)**. Open this file in any text editor, and copy and paste the contents into Sevalla.
Certificates can expire, so you may need to update this in the future. Company Owners and Company Administrators will receive a notification three weeks prior to certificate expiration to ensure the certificate is updated in a timely manner.
Click **Continue**.
## Test the authentication in Sevalla
You cannot enable SAML SSO within Sevalla without first testing the authentication.
In Sevalla, within Single sign-on, click **Continue** until you are on the **Test and finish** tab, and click **Test authentication**.
A notification appears if the test was successful or if the test fails.
If the test fails, click **Back** and check your SAML settings within your IdP and within Sevalla.
If the test is successful and you want to enable SAML, click **Save and set SSO live**.
Your Sevalla company users will now be able to sign in with SAML SSO or by entering their username and password. Users who sign in through an IdP are not required to complete Sevalla's 2FA, as authentication is handled directly by the IdP.
If you want to force users to sign on via SAML, you can enable Mandatory SSO and add Exceptions. You can also enable JIT provisioning to allow users authorized by your IdP to access your Sevalla company without requiring an invitation.
## Change the session duration
Your Identity Provider (IdP) determines how long your SSO session remains active and when it expires. If your IdP doesn’t specify a session duration, Sevalla defaults to a 24-hour session.
When your SSO session expires, you’ll be logged out of SSO. If you’re working within a company that uses SSO, you’ll be prompted to reauthenticate. If you have access to multiple companies in Sevalla, you’ll remain logged in overall but will need to reauthenticate before accessing any company that requires SSO.
For details on adjusting session duration, refer to the [Ping Identity documentation](https://docs.pingidentity.com/pingone/directory/p1_manage_user_sessions_intro.html?_gl=1*7iinwk*_gcl_au*MTMwMzMwNjQ5My4xNzYyNTEyOTgy*_ga*MjA5MzYyMDUzMy4xNzYyNTEyOTcx*_ga_V94KKVLZPT*czE3NjI3Nzk4MTQkbzMkZzEkdDE3NjI3Nzk4MjYkajQ4JGwwJGg4MzI3NjA4OA..).
# User management
Source: https://docs.sevalla.com/company-settings/user-management
Add, remove, and manage users in your company account.
With our [multi-user feature](https://kinsta.com/blog/manage-users-hosting-account/), you can create and manage a team, giving them access to various aspects of your applications, databases, or static sites. We offer a number of roles to allow you to fine-tune user access. This article explains the various capabilities you can give to your users.
Sevalla uses [Two-Factor Authentication (2FA)](https://docs.sevalla.com/user-settings/logging-in#two-factor-authentication-2fa) for all users to help protect your Sevalla account from unauthorized access, giving you enhanced security and greater peace of mind. 2FA requires an additional verification code sent to your email or available through an authentication or password manager app. You can see which authentication method each user has enabled (email or app authentication) within **Company settings** > **User management** > **2FA**.
## User roles
### Company Owner role
There is a special role called the **Company Owner**. A **Company Owner** is always also a **Company Administrator**. There can only be one **Company Owner** per company.
A **Company Owner** is the only user in a company who can request an account closure or [transfer company ownership](/company-settings/overview/#transfer-company-ownership) (to a **Company Administrator** in the same account). Apart from that, they are exactly like **Company Administrators** in day-to-day use.
### Company roles
When [inviting or modifying a user](#invite-a-user), the first choice is to give the user **Company access** or **Service access**. Service-level users only have access to specific applications, databases, static sites, or object storage containers you assign to them, while company users see company-level details. There are three company-level user roles to choose from, with various levels of access based on their role.
All user roles have access to Sevalla’s Support, which is powered by Stella, our AI support agent built on Claude, available through the chat system directly inside Sevalla. Stella is the first point of contact for all customers and can resolve most common questions and issues. Customers are initially assisted by Stella, with human support available directly to customers above a certain spending level.
#### Company Administrator
**Company Administrators** have the highest level of access. They have complete control of all company data and full access to all services, including DNS in Sevalla and migration requests. Only give **Company Administrator** access to users whom you trust.
#### Company Developer
A **Company Developer** has access to add and remove applications and databases, manage all services and DNS in Sevalla, and can manage service-level users. While a **Company Developer** can view the list of company users (including email addresses and roles), they cannot make any changes to company-level users.
Company Developers do not see billing details or company settings. The following actions are billing events that a company developer does **not** have access to:
* Change the build resources for an application.
* Change the pod size or the number of instances for an application process.
* Change the database size.
* Add or remove an add-on.
If you want a **Company Developer** to access any of the above features, you must increase their access level to **Company Administrator**.
#### Company Billing
A **Company Billing** user only sees billing details and company settings. They can see invoices, enable automatic invoice emails, and modify company details like name and address. They do not have access to any sites, applications, databases, or object storage containers in any way.
### Service roles
Service-level users can access a specific site, application, database, or object storage container. They may have access to more than one service, such as an application or two applications and a database.
#### Static Site Administrator
**Static Site Administrators** have complete access to the site they are given access to, with the exception of removing the static site. A single user can be a **Static Site Administrator** for multiple sites.
#### Application Administrator
**Application Administrators** have complete access to the application to which they are given access, with the exception of removing the application. A single user can be an **Application Administrator** for multiple applications.
#### Database Administrator
**Database Administrators** have complete access to the database to which they are given access, with the exception of removing the database. A single user can be a Database **Administrator** for multiple databases.
#### Object Storage Administrator
**Object Storage Administrators** have complete access to the object storage container to which they are given access, with the exception of removing the container. A single user can be an Object Storage **Administrator** for multiple containers.
#### Project Administrator
**Project Administrators** have access to the details of the projects. They can add new services to a project and fully manage any of the services they have added. They cannot add new projects, add existing services to a project, or delete a project.
They can also manage user access within their projects, allowing them to control who can access project resources without requiring company-level permissions. They can:
* Invite new or existing users to a project as a Project Administrator or Project Developer.
* Manage user roles within their projects.
* Control service-level access for applications and databases within their projects.
* Convert user access from service-level to project-level, provided the user has access to all services within that project and no others.
Project Administrators cannot manage company-level users, modify users in projects they do not administer, or change access for users who have service-level permissions outside of their projects.
#### Project Developer
**Project Developers** have access to the details of the projects. They can add new services to a project and fully manage any of the services they have added. They cannot add new projects, add existing services to a project, or delete a project. A single user can be a **Project Developer** for multiple projects.
### Sevalla user roles and permissions chart
The following chart provides more specific details about the capabilities each user role has.
| Capability | Company Owner | Company Administrator | Company Developer | Company Billing | Service-level Administrator | Project Administrator | Project Developer |
| ---------------------------------------------------------------------------------- | ------------- | --------------------- | ----------------- | --------------- | --------------------------- | ------------------------------- | ------------------------------- |
| Access billing details or change plan | Yes | Yes | No | Yes | No | No | No |
| Manage all sites, applications, databases, or object storage containers | Yes | Yes | Yes | No | No | Only those created in a project | Only those created in a project |
| Manage one site, application, database, or object storage container | Yes | Yes | Yes | No | Yes | Only those created in a project | Only those created in a project |
| Install or remove a paid add-on | Yes | Yes | No | Yes | No | No | No |
| Request 2FA be disabled for other users in a company\* | Yes | No | No | No | No | No | No |
| Add, suspend, or delete a site, application, database, or object storage container | Yes | Yes | Yes | No | No | Only those created in a project | Only those created in a project |
| Access site, application, or database analytics | Yes | Yes | Yes | No | Yes | Only those created in a project | Only those created in a project |
| Request persistent storage backup restoration | Yes | Yes | No | No | No | No | No |
| Create projects | Yes | Yes | Yes | No | No | No | No |
| Add existing services to a project | Yes | Yes | Yes | No | No | No | No |
| Add new services to a project | Yes | Yes | Yes | No | No | Yes | Yes |
\*Can request this if the user is only in one company.
## Invite a user
With our multi-user feature, you can create and manage a team and give them access to various aspects of your sites, applications, databases, or object storage. On the Company Users page, you can invite users to your company or services.
After you invite a user, they will receive a notification email inviting them to your company. If they do not have a Sevalla account, they’ll need to sign up for one or use Single Sign-On (SSO) to log in and access the company they’ve been invited to.
To invite a user to your company, go to **Company settings** > **User management** > **Invite users**.
Enter the email address of the user you’d like to invite. You can invite up to 10 users by separating their email addresses with commas in the email field.
Select **Company** to choose between **Company administrator**, **Company developer**, or **Company billing**.
If you want to grant access only to a particular project, select **Project**, choose the project you want the user to have access to, and either type the project's name or select it from the list.
Project access is only shown if a project exists within the company.
If you want to grant access only to a particular service, select **Service**, choose the service you want the user to have access to, and either type the service's name or select it from the list.
Click **Send invitation** to invite the users.
## Resend or cancel a user invitation
If you need to send the invitation to a user again, click the ellipsis (three dots) on the user, click **Copy invitation link**, and send it to them. If you need to cancel the pending invitation, click **Cancel invitation**.
## Update a user's access level
If you want to change a user's access level, click **Company settings** > **User management**, click the ellipsis (three dots) on the user, and click **Update**.
Select the new level of company or service access, and click **Update access**.
## Remove a user
Removing a user from a company will also remove that user from all sites, applications, or databases associated with the company. The user does not receive any notification when they are removed. If you want the user to have access to one or more services but not company access, you can invite them and only give them access to the required services.
Removing a user does not automatically revoke access to any API keys they may have had. You should review your API keys and revoke access to any that the user may have had access to within **Company settings** > **API keys** > **Revoke**.
To remove a user, click **Company settings** > **User management**, click the ellipsis (three dots) on the user, and click **Delete**. You can also remove the user within the service **Access management** page.
Confirm the deletion by clicking **Continue**.
# Databases - Analytics
Source: https://docs.sevalla.com/databases/analytics
Monitor your database performance and analytics in real time.
Sevalla charges for [Database Hosting](https://sevalla.com/database-hosting/) based on the size, runtime, and egress bandwidth (when applicable) of your database. With Database Analytics, you can get insights into your database's usage data. You can view analytics for each database in database-level analytics or for all of your databases in company-level analytics. For more information about how your usage is calculated and how it appears on your invoice, refer to [Database Pricing](/billing/database-pricing).
The database billing amounts are also included in the **Spending overview** chart on your Sevalla Dashboard. This chart shows the spending overview for all Sevalla services.
## Database analytics
Database analytics shows you information about your database's storage, memory, and CPU usage.
When viewing the database analytics, you can choose to see data for the past 1 hour, 6 hours, 12 hours, 1 day, 2 days, 4 days, 7 days, 14 days, or 30 days, or select a specific date and time period. You can refresh the chart data at any time.
When you hover over a chart, a corresponding reference line appears on the other charts on the same page. You can click and drag this reference line to zoom into a specific time period, and all charts on the page will update to show that same time range.
Select **Show limit** to compare your usage with your current plan limit.
To access these in-depth reports, go to your database's **Analytics** page (**Databases** > ***dbname*** > **Analytics**).
### Storage usage
The Storage usage chart shows the data stored in the database (including any add-on storage) for the selected time period. Select **Show limit** to compare your usage to your service's resource limit.
Relational databases such as MariaDB and MySQL organize data in predefined relationships where data is stored in tables (or "relations") of columns and rows to make it easy to see and understand how different data structures relate to each other. This means the database size includes these relations and, therefore, will always be larger than the actual data in the database.
### Memory usage
The Memory usage chart shows the average of the total memory (RAM) used for the selected time period. Select **Show limit** to compare your usage to your service's resource limit. If a database is using most or all of the memory available, we recommend a larger database type with more available memory. You can increase the size in your [**Database Settings**](/databases/settings) (**Database Settings** > **Update details**) if you need a larger database.
Due to the size of the databases in Database Hosting plans 7-9, to ensure the stability and speed of the database application, the amount of usable RAM and CPU may be 4.4% – 9.4% less than indicated. These resources remain dedicated to the underlying system that runs your database.
### CPU usage
The CPU usage chart shows the average of the total CPU utilization for the selected time period, expressed as a percentage of the instance's CPU resources. Select **Show limit** to compare your usage to your service's resource limit. If you see a high percentage of CPU usage (near 100%), we recommend a larger database type with more available CPU. You can change the size in your [**Database Settings**](/databases/settings) (**Database Settings** > **Update details**) if you need a larger database.
## Additional notes
Analytics data is retained for 30 days. We suggest checking your **Database Analytics** frequently after first creating your Database at Sevalla and periodically thereafter. If you see any unexplained analytics data or inconsistencies that concern you, let our Support team know, and we can further investigate to help determine the cause.
# Backups
Source: https://docs.sevalla.com/databases/backups
Manage automated and manual database backups.
The database **Backups** page shows the automatic daily backups and any manually created backups you've made of your database. You can also restore a backup, create a new manual backup, or delete a manual backup.
To download a database backup, you'll need to either export your database via the command line or use a database tool like TablePlus.
Database backups are excluded when [calculating your total disk space](/databases/analytics) (i.e. storage).
## Automatic backups
Databases are automatically backed up daily, and each backup is **stored for 7 days**.
## Manual backups
You can manually create a database backup at any time, up to 5 manual backups, which are **stored for 14 days**. If you need to make more than 5 manual backups in 14 days, you'll need to delete one of the manual backups to make room for a new one.
To create a manual backup, click **Create backup**, enter a note to identify your backup (required), and click **Create database backup**.
## Restore a backup
You can restore automatic or manual backups in Sevalla to your current database or to another database.
Restoring a database backup overwrites the target database content with the content from the backup. Your database credentials and external connection details will not change.
To restore a backup, click the ellipsis (three dots) next to the backup you want to restore, and click **Restore**.
Choose whether you want to restore the backup to the current database or a different database.
If you restore to a different database, your current database is untouched. The target database must:
* Belong to the same company
* Be the same database type
* Be located in the same data center
Click **Restore backup**.
The restoration may take several minutes or more, depending on the size of your database.
# Add a database
Source: https://docs.sevalla.com/databases/get-started/add-a-database
Follow these steps to add a new database to Sevalla's Database Hosting.
We currently offer 5 different database types to fulfill various data storage needs:
* **Redis** 5.0, 6.x, 7.x, and 8.x
* **MariaDB** 10.4, 10.5, 10.6, 10.11, 11.0, and 11.1
* **PostgreSQL** 9.6, 10, 11, 12, 13, 14, 15, 16, and 17
* **MySQL** 8.0 and 9.0
* **Valkey** 7.2
You can attach databases to applications or run databases by themselves.
It’s also possible to utilize a Dockerfile and persistent storage to deploy other types of databases on Application Hosting.
## Add a database
Only **Company Owners** and **Company Administrators** can add a new database. For more information about user roles and permissions, refer to [User Management](/company-settings/user-management/).
To add a database, within **Databases**, click **Create database**.
* **Type** and **version:** The database software and version you want to use. Currently, we support:
* **Redis** 5.0, 6.x, 7.x, and 8.x
* **MariaDB** 10.4, 10.5, 10.6, 10.11, 11.0, and 11.1
* **PostgreSQL** 9.6, 10, 11, 12, 13, 14, 15, 16, and 17
* **MySQL** 8.0 and 9.0
* **Valkey** 7.2
* **Enable pgvector extension:** This option is only available for new databases on PostgreSQL. This extension enables fast vector similarity search, making it easy to store and query high-dimensional vectors. Commonly used in AI, machine learning, and recommendation systems, it helps compare vector embeddings efficiently.
* **Enable PostGIS extension:** This option is only available for new databases on PostgreSQL. This adds support for geographic and spatial data types, enabling advanced location-based queries and operations. It allows PostgreSQL to store, query, and analyze geographic objects such as points, lines, and polygons. It adds the following extensions to your database:
* `postgis`
* `postgis_topology`
* `postgis_tiger_geocoder`
* `fuzzystrmatch`
* `address_standardizer`
* `address_standardizer_data_us`
* **Database name:** The name of the database that you will use to connect to it. By default, this is populated with three random words. Some database names are restricted for security reasons. The [full list of invalid database names](#invalid-database-names-and-database-usernames) is shown below.
* **Database user:** This only applies to PostgreSQL, MySQL, and MariaDB. This is the username you want to use to connect to the database. By default, this is populated with a random word. Once tied to an application, we can auto-populate your environment variables with this data. Some database usernames are restricted for security reasons. The [full list of invalid database usernames](#invalid-database-names-and-database-usernames) is shown below.
Each database instance includes one database and one database user, both defined when the instance is created. Currently, the database user does not have superuser or administrative privileges, so you cannot create additional databases or database users within the same instance. If you need another database or user, create a new database instance.
* **Database password:** The password you want to use to connect to the database. We recommend leaving this as-is. Once tied to an application, we can auto-populate your environment variables with this data.
* **Display name:** The name that will be shown in Sevalla. By default, this is populated with the same three random words as the **Database name**.
* **Project:** This option is only shown if your company already has at least one project. Select the project you’d like to add the database to, or leave it blank to keep the database at the company level instead of assigning it to a specific project.
* **Location:** Choose the [data center](/service-information/data-center-locations/) you want to use for this database. By default, this is populated with the location closest to you.
Currently, internal connections are only supported between applications and databases in the same region. If you’d like to use a database with your application, you can create the database at Sevalla and use an internal connection between the two (on the application’s **Settings** page or the database’s **Info** page).
* **Resource:** Choose the resources you will need for this database. If you need to increase the size in the future, you can do so within **Settings** > **Update details**.
Relational databases such as MariaDB and MySQL organize data in predefined relationships where data is stored in tables (or “relations”) of columns and rows to make it easy to see and understand how different data structures relate to each other. This means the database size includes these relations and, therefore, will always be larger than the actual data in the database.
**Overview** allows you to review your database’s costs. To create the database, click **Create database**.
### Invalid MySQL database names and usernames:
* mysql
* information\_schema
* performance\_schema
* sys
### Invalid PostgreSQL database names and usernames:
* postgres
* template0
* template1
* information\_schema
* performance\_schema
* sys
# Databases - Features
Source: https://docs.sevalla.com/databases/get-started/features
Discover the database features offered by the platform.
Sevalla’s Database Hosting supports the latest version of MariaDB, MySQL, PostgreSQL, and Redis, and you can host your database on one of [25 data centers](/service-information/data-center-locations). You can create a brand [new database](/databases/get-started/add-a-database) or [import an existing one](/databases/import-export/postgresql) directly onto the Sevalla infrastructure. You choose the [resources](https://sevalla.com/database-hosting/pricing/) to best suit your database requirements, including CPU count, RAM, and storage space.
Database Hosting includes the following features:
* **Unlimited users**: You can invite as many [users](/company-settings/user-management) as required to your company or site with different levels of access, depending on what their role is.
* **Unlimited databases**: You can [add as many databases](/databases/get-started/add-a-database) as you want within your company, each with the resources required for the specific database.
* **Unlimited usage**: There are no row limits or query count limits.
* **Automatic backups**: We automatically create daily [backups](/databases/backups) of your database, and you can create up to 5 manual backups with no impact on your storage space.
* **Analytics**: Sevalla’s [Analytics](/databases/analytics) provides you with in-depth information about your database’s usage.
* **Private network**: If you host both your database and application on Sevalla, you can set up an [internal connection](/databases/connections) to create a private network so everything is on the same cluster and you don’t get charged for ingress traffic.
# Databases - Infrastructure
Source: https://docs.sevalla.com/databases/get-started/infrastructure
Learn more about the database infrastructure and hosting details.
When you host your database with Sevalla, your projects run on Sevalla’s top-tier infrastructure. In this guide, we’ll dive a little into the details of our [Application Hosting Infrastructure](/applications/get-started/infrastructure). For more information about how this works with Sevalla’s Application Hosting, refer to [Application Hosting Infrastructure](/applications/get-started/infrastructure).
## Sevalla add database
In Sevalla, when you [add a database](/databases/get-started/add-a-database), the database image is pushed to the Kubernetes cluster.
## Kubernetes cluster
This is a virtual machine (VM) where multiple containers can run. The clusters are tuned to ensure the request from the artifact registry finds the right container, the containers are running, and they have the right resources.
Our Kubernetes infrastructure supports a multi-tenant setup, where each database runs in its own containerized environment. Network isolation and multi-layer virtualization ensure security and prevent unauthorized access between databases. This design provides you with a reliable and secure hosting platform, enabling you to focus on your core business while we handle the underlying infrastructure. We deploy at least one cluster per region, with the potential for additional clusters based on the number of databases in each region. This system ensures optimal resource allocation and scalability to meet the growing needs of our clients.
## Requests
If you’re using an internal connection from an application hosted on Sevalla to a database hosted on Sevalla, when a visitor accesses the website for an application, it first accesses Cloudflare, which knows which cluster hosts the website. It then sends the access request to the correct cluster.
Currently, for Application and Database Hosting, Cloudflare includes the default firewall rules, DDoS protection, and other defaults.
Each cluster has a load balancer that receives the access request from Cloudflare and randomly pushes a VM worker node.
The VM worker node receives the request on the Ingress system, which knows which container is responsible for the hostname being requested. The Ingress system sends the request to the correct container, and if the container has a database attached, it communicates with the database and sends a response on the same route.
A virtual machine (VM) can hold multiple containers and multiple databases.
Each container can have multiple copies on the VM. In this case, the Ingress system knows this and randomly sends through one of the copies of the same container.
## External connection
You can [connect](/databases/connections) to your database via the command line (CLI) or with a database tool. An external connection makes an internet round-trip, so it is much slower than internal communication. We recommend external connections if you are hosting only your database with us, but not your front end.
# MariaDB
Source: https://docs.sevalla.com/databases/import-export/mariadb
Guide to importing and exporting MariaDB databases.
MariaDB is an open-source relational database management system commonly used in applications. With Sevalla’s Database Hosting, you can easily add a new MariaDB database from the dashboard, click **Databases** > [**Create database**](/databases/get-started/add-a-database)**,** and select the required options.
If you have an existing database locally or with another hosting provider, you can import the MariaDB database into Sevalla’s Database Hosting using a third-party database tool or the Command Line Interface (CLI).
To import a database, you must create a new database in Sevalla first.
## Import a MariaDB database using a database tool
There are many database tools you can use to connect and manage your database; we have step-by-step instructions for [TablePlus](/databases/manage-data/tableplus), which allows you to manage all the database types you can host on Sevalla.
You can use any database client or tool that supports your database type. While some specifics, like navigation and field names, may vary between database tools, the fundamental concepts are the same.
## Import a MariaDB database using the command line interface (CLI)
You can use the command line interface (CLI) to import your MariaDB database into Sevalla. The installation of the database server and commands vary for each database type. This article is specific to MariaDB. For other database types, see:
* [MySQL](/databases/import-export/mysql)
* [PostgreSQL](/databases/import-export/postgresql)
* [Redis](/databases/import-export/redis)
* [Valkey](/databases/import-export/valkey)
### Install MariaDB
If you do not yet have MariaDB installed on your local machine, you’ll need to install it to connect to your database. Depending on your operating system, you can install MariaDB in the following ways.
#### Windows
Download and install the [Maria DB GUI Server](https://mariadb.org/download/?t=mariadb\&p=mariadb\&r=10.11.2).
#### MacOS
With [Homebrew](https://brew.sh/), replace X in the following command with the minor version of MariaDB you want to install:
```
brew install [[email protected]](/cdn-cgi/l/email-protection)
```
#### Linux
Use the [MariaDB Server repository](https://mariadb.org/download/?t=repo-config) and install `mariadb-client`.
### Sevalla database credentials
You can find your database credentials under [**External connections**](/databases/connections) on the database **Overview** page.
### Import a MariaDB database
Use the following command to export the database, replacing EXTERNAL\_HOSTNAME, USERNAME, PORT, and DATABASE\_NAME with the information from your database’s **External connections**. Replace **export.sql** with the path and name of the database you want to import:
```
mariadb -h EXTERNAL_HOSTNAME -u USERNAME -P PORT -p DATABASE_NAME < export.sql
```
When prompted, enter the database password.
No output will be produced unless there are errors, which will be printed to the command line. To verify a successful import, you can use `SHOW TABLES;` or a similar command to review the data in your database.
### Export a MariaDB database
Use the following command to export the database, replacing EXTERNAL\_HOSTNAME, USERNAME, PORT, and DATABASE\_NAME with the information from your database’s **External connections**. Replace **export.sql** with the path and file name of the database you want to export:
```
mariadb-dump --no-tablespaces -h EXTERNAL_HOSTNAME -u USERNAME -P PORT -p DATABASE_NAME > export.sql
```
When prompted, enter the database password.
Once the export is complete, your database file (e.g. **export.sql**) will be available at the path you specified in the `mariadb-dump` command. You can open the file with a [plain text editor](https://kinsta.com/blog/best-text-editors/) (e.g. TextEdit, Notepad++, Sublime Text, etc.) or a database tool like TablePlus to review the exported data.
# MySQL
Source: https://docs.sevalla.com/databases/import-export/mysql
Guide to importing and exporting MySQL databases.
MySQL is a widely used relational database system for managing structured data. With Sevalla’s Database Hosting, to add a new MySQL database from the dashboard, click **Databases** > [**Create database**](/databases/get-started/add-a-database)**,** and select the required options.
If you have an existing database locally or with another hosting provider, you can import the MySQL database into Sevalla’s Database Hosting using a third-party database tool or the Command Line Interface (CLI).
To import a database, you must create a new database in Sevalla first.
## Import a MySQL database using a database tool
There are many database tools you can use to connect and manage your database; we have step-by-step instructions for [TablePlus](/databases/manage-data/tableplus), which allows you to manage all the database types you can host on Sevalla.
You can use any database client or tool that supports your database type. While some specifics, like navigation and field names, may vary between database tools, the fundamental concepts are the same.
## Import a MySQL database using the command line interface (CLI)
You can use the command line interface (CLI) to import your MySQL database into Sevalla. The installation of the database server and commands vary for each database type. This article is specific to MySQL. For other database types, see:
* [MariaDB](/databases/import-export/mariadb)
* [PostgreSQL](/databases/import-export/postgresql)
* [Redis](/databases/import-export/redis)
* [Valkey](/databases/import-export/valkey)
### Install MySQL
If you do not yet have MySQL installed on your local machine, you’ll need to install it to connect to your database. Depending on your operating system, you can install MySQL in the following ways.
#### Windows
Download and install [MySQL Community Server](https://dev.mysql.com/downloads/mysql/) (GUI program).
#### MacOS
Choose one of the following options for installing MySQL on MacOS:
* With [Homebrew](https://brew.sh/): `brew install mysql`.
* Download and install [MySQL Community Server](https://dev.mysql.com/downloads/mysql/) (GUI program).
#### Debian-based Linux (Debian, Ubuntu, Mint, etc.)
Use the official [MySQL APT repository](https://dev.mysql.com/doc/refman/8.0/en/linux-installation-apt-repo.html) and install the `mysql-client` package.
#### RedHat-based Linux (RedHat Fedora, CentOS, etc.)
Use the official [MySQL Yum repository](https://dev.mysql.com/doc/refman/8.0/en/linux-installation-yum-repo.html) and install the `mysql-client` package.
### Sevalla database credentials
You can find your database credentials under [**External connections**](/databases/connections) on the database **Overview** page.
### Import a MySQL database
Use the following command to export the database, replacing `EXTERNAL_HOSTNAME`, `USERNAME`, `PORT`, and `DATABASE_NAME` with the information from your database’s **External connections**. Replace **export.sql** with the path and name of the database you want to import:
```
mysql -h EXTERNAL_HOSTNAME -u USERNAME -P PORT -p DATABASE_NAME < export.sql
```
When prompted, enter the database password.
No output will be produced unless there are errors, which will be printed to the command line. To verify a successful import, you can use `SHOW TABLES;` or a similar command to review the data in your database.
### Export a MySQL database
Use the following command to export the database, replacing `EXTERNAL_HOSTNAME`, `USERNAME`, `PORT`, and `DATABASE_NAME` with the information from your database’s **External connections**. Replace **export.sql** with the path and file name of the database you want to export:
```
mysqldump --no-tablespaces -h EXTERNAL_HOSTNAME -u USERNAME -P PORT -p DATABASE_NAME > export.sql
```
When prompted, enter the database password.
Once the export is complete, your database file (e.g. **export.sql**) will be available at the path you specified in the `mysqldump` command. You can open the file with a [plain text editor](https://kinsta.com/blog/best-text-editors/) (e.g. TextEdit, Notepad++, Sublime Text, etc.) or a database tool like TablePlus to review the exported data.
# PostgreSQL
Source: https://docs.sevalla.com/databases/import-export/postgresql
Guide to importing and exporting PostgreSQL databases.
PostgreSQL is an advanced open-source relational database management system widely used in applications. With Sevalla's Database Hosting, you can easily add a new PostgreSQL database from the dashboard, click **Databases** > [**Create database**](/databases/get-started/add-a-database)**,** and select the required options. When adding a new PostgreSQL database, you can enable the pgvector extension to store and query high-dimensional vectors efficiently. This is especially useful for AI, machine learning, and recommendation systems that rely on vector comparisons.
If you have an existing database locally or with another hosting provider, you can import the PostgreSQL database into Sevalla's Database Hosting using a third-party database tool or the Command Line Interface (CLI).
To import a database, you must create a new database in Sevalla first.
## Import a PostgreSQL database using a database tool
There are many database tools you can use to connect and manage your database; we have step-by-step instructions for [TablePlus](/databases/manage-data/tableplus), which allows you to manage all the database types you can host on Sevalla.
You can use any database client or tool that supports your database type. While some specifics, like navigation and field names, may vary between database tools, the fundamental concepts are the same.
## Import a PostgreSQL database using the command line interface (CLI)
You can use the command line interface (CLI) to import your PostgreSQL database into Sevalla. The installation of the database server and commands vary for each database type. This article is specific to PostgreSQL. For other database types, see:
* [MySQL](/databases/import-export/mysql)
* [MariaDB](/databases/import-export/mariadb)
* [Redis](/databases/import-export/redis)
* [Valkey](/databases/import-export/valkey)
### Install PostgreSQL
If you do not yet have PostgreSQL installed on your local machine, you'll need to install it to connect to your database. Depending on your operating system, you can install PostgreSQL in the following ways.
#### Windows
Download and install the GUI installer or binaries for the [Interactive installer by EDB](https://www.postgresql.org/download/windows/).
#### MacOS
With [Homebrew](https://brew.sh/), replace XX in the following command with the version of PostgreSQL you want to install:
```
brew install postgresql@XX
```
#### Debian-based Linux (Debian, Ubuntu, Mint, etc.)
Use the [PostgreSQL APT repository](https://mariadb.org/download/?t=repo-config) and install the `postgresql-client`.
#### RedHat-based Linux (RedHat Fedora, CentOS, etc.)
Use the [PostgreSQL Yum repository](https://www.postgresql.org/download/linux/redhat/) and install the `postgresql-client`.
### Sevalla database credentials
You can find your database credentials under [**External connections**](/databases/connections) on the database **Overview** page.
### Import a PostgreSQL database
Use the following command to export the database, replacing EXTERNAL\_HOSTNAME, USERNAME, PORT, and DATABASE\_NAME with the information from your database's **External connections**. Replace **export.sql** with the path and name of the database you want to import:
```
psql -h EXTERNAL_HOSTNAME -U USERNAME -p PORT -d DATABASE_NAME < export.sql
```
When prompted, enter the database password.
No output will be produced unless there are errors, which will be printed to the command line. To verify a successful import, you can use dt or a similar command to review the data in your database.
If your database file is an archive format (e.g. .dump or .tar) you'll need to use pg\_restore instead of psql.
### Export a PostgreSQL database
Use the following command to export the database, replacing EXTERNAL\_HOSTNAME, USERNAME, PORT, and DATABASE\_NAME with the information from your database's **External connections**. Replace **export.sql** with the path and file name of the database you want to export:
```
pg_dump -h EXTERNAL_HOSTNAME -U USERNAME -p PORT -d DATABASE_NAME > export.sql
```
When prompted, enter the database password.
Once the export is complete, your database file (e.g. **export.sql**) will be available at the path you specified in the `pg_dump` command. You can open a .sql file with a [plain text editor](https://kinsta.com/blog/best-text-editors/) (e.g. TextEdit, Notepad++, Sublime Text, etc.) or a database tool like TablePlus to review the exported data.
If you're working with a large database, you may want to export the database as an archive file (e.g. .dump or .tar) to save space and make exporting quicker. To view the data in an archive file, you will need to restore the file to a database.
# Redis
Source: https://docs.sevalla.com/databases/import-export/redis
Guide to importing and exporting Redis databases.
Redis is an open-source, in-memory data structure that allows users to store, manipulate, and retrieve data structures in memory. With Sevalla’s Database Hosting, you can easily add a new Redis database from the dashboard, click **Databases** > [**Create database**](/databases/get-started/add-a-database), and select the required options.
If you have an existing database locally or with another hosting provider, you can import the Redis database into Sevalla’s Database Hosting using a third-party database tool. You cannot currently import a Redis database via the command line.
To import a database, you must create a new database in Sevalla first.
## Import a Redis database using a database tool
There are many database tools you can use to connect and manage your database; we have step-by-step instructions for [TablePlus](/databases/manage-data/tableplus), which allows you to manage all the database types you can host on Sevalla.
You can use any database client or tool that supports your database type. While some specifics, like navigation and field names, may vary between database tools, the fundamental concepts are the same.
## Export a Redis database using the command line interface (CLI)
You cannot currently import a Redis database to Sevalla’s Database Hosting via the command line. As a workaround, you can use a database client like TablePlus to import your Redis database to Sevalla.
You can use the command line interface (CLI) to export your Redis database from Sevalla. The installation of the database server and commands vary for each database type. This article is specific to Redis. For other database types, see:
* [MySQL](/databases/import-export/mysql)
* [MariaDB](/databases/import-export/mariadb)
* [PostgreSQL](/databases/import-export/postgresql)
* [Valkey](/databases/import-export/valkey)
### Install Redis
If you do not yet have Redis installed on your local machine, you’ll need to install it to connect to your database. Depending on your operating system, you can install Redis in the following ways.
#### Windows
Redis is not currently supported on Windows, but you can use the [Windows Subsystem for Linux (WSL2)](https://learn.microsoft.com/en-us/windows/wsl/install) and follow the Debian-based Linux instructions as a workaround.
#### MacOS
With [Homebrew](https://brew.sh/): `brew install redis`.
#### Debian-based Linux (Debian, Ubuntu, Mint, etc.)
Use the official [packages.redis.io APT repository](https://redis.io/docs/latest/operate/oss_and_stack/install/archive/install-redis/install-redis-on-linux/).
#### RedHat-based Linux (RedHat Fedora, CentOS, etc.)
Install via [snap](https://snapcraft.io/docs/installing-snapd): `sudo snap install redis`.
### Sevalla database credentials
You can find your database credentials under [**External connections**](/databases/connections) on the database **Overview** page.
### Export a Redis database
Use the following command to export the database, replacing EXTERNAL\_HOSTNAME, PORT, and PASSWORD with the information from your database’s **External connections**. Replace **export.rdb** with the path and file name of the database you want to export:
```
redis-cli -h EXTERNAL_HOSTNAME -p PORT -a PASSWORD --rdb export.rdb
```
Once the export is complete, your database file (e.g. **export.rdb**) will be available at the path you specified in the `redis-cli` command.
# Valkey
Source: https://docs.sevalla.com/databases/import-export/valkey
Guide to importing and exporting Valkey databases.
[Valkey](https://valkey.io/) serves as an alternative to the Redis NoSQL data store. It is an open-source in-memory data store that supports a variety of workloads and data structures. With Sevalla’s Database Hosting, you can easily add a new Valkey database from the dashboard, click **Databases** > [**Create database**](/databases/get-started/add-a-database), and select the required options.
If you have an existing database locally or with another hosting provider, you can import the Valkey database into Sevalla’s Database Hosting using a third-party database tool. You cannot currently import a Valkey database via the command line.
To import a database, you must create a new database in Sevalla first.
## Import a Valkey database using a database tool
There are many database tools you can use to connect and manage your database; we have step-by-step instructions for [TablePlus](/databases/manage-data/tableplus), which allows you to manage all the database types you can host on Sevalla.
When using TablePlus to connect to a Valkey database, you must choose Redis as the database type.
You can use any database client or tool that supports your database type. While some specifics, like navigation and field names, may vary between database tools, the fundamental concepts are the same.
## Export a Valkey database using the command line interface (CLI)
You cannot currently import a Valkey database to Sevalla’s Database Hosting via the command line. As a workaround, you can use a database client like [TablePlus](/databases/manage-data/tableplus) to import your Valkey database to Sevalla.
When using TablePlus to connect to a Valkey database, you must choose Redis as the database type.
You can use the command line interface (CLI) to export your Valkey database from Sevalla. The installation of the database server and commands vary for each database type. This article is specific to Valkey. For other database types, see:
* [MySQL](/databases/import-export/mysql)
* [MariaDB](/databases/import-export/mariadb)
* [PostgreSQL](/databases/import-export/postgresql)
* [Redis](/databases/import-export/redis)
### Install Valkey
If you do not yet have Valkey installed on your local machine, you’ll need to install it to connect to your database. Refer to [Valkey’s installation instructions](https://github.com/valkey-io/valkey).
### Sevalla database credentials
You can find your database credentials under [**External connections**](/databases/connections) on the database **Overview** page.
### Export a Valkey database
Use the following command to export the database, replacing EXTERNAL\_HOSTNAME, PORT, and PASSWORD with the information from your database’s **External connections**. Replace **export.rdb** with the path and file name of the database you want to export:
```
redis-cli -h EXTERNAL_HOSTNAME -p PORT -a PASSWORD --rdb export.rdb
```
Once the export is complete, your database file (e.g. **export.rdb**) will be available at the path you specified in the `redis-cli` command.
# Database Studio
Source: https://docs.sevalla.com/databases/manage-data/database-studio
Use the integrated Database Studio to run queries and manage your database.
With the Database Studio, you can manage your MySQL, MariaDB, and PostgreSQL databases right from the Sevalla UI. It allows you to run queries, view data, and more without having to use an external tool or download your database.
To access the Database Studio, go to your database and click **Studio**.
## Sort your data
Within the Database Studio, you can sort the columns by using the arrows at the top of each column; you can also choose which columns you want to show using the **Columns** option. You can use **Filters** to show specific data, and you can apply more than one filter at a time. When a filter is applied, it shows an exclamation mark on the **Filters** option.
To open and edit the filter within the [SQL console](#sql-console), click **Open in SQL**.
You can create customized views of your database for easier access to the data you need. Click the plus icon, then select **Create View**. From there, you can give your view a name, choose the tables and columns to display, and apply any necessary conditions.
To open and edit the view within the [SQL console](#sql-console), click **Open in SQL console**.
## Export your database
Within the Database studio, you can export your entire database or just selected data to a `.json`, `.csv`, or `.xlsx` file. To export your data, click the ellipsis (three dots) and choose the file type you want to export to.
## SQL console
Within the Database studio, you can access an SQL console where you can run SQL queries on your database. The SQL editor lets you view the **Database Schema**, **Prettify** the code for better readability, and **Run** the SQL directly in the console. When you run the SQL query, you can choose to show the results as a table or as JSON, and export the results to a `.json`, `.csv`, or `.xlsx` file. You can also store these queries as snippets and create folders to organize the snippets.
## Add a record
To add a record to your database, click **Add record**, enter the required data into the table, and click **Save x change(s)**.
## Add a table
To add another table to your database, click the plus icon and then **Create Table**. You can then name the table and define its columns, specifying the data type, constraints, default values, and expressions for any generated data. Additionally, you can add table-level constraints and indexes as needed.
Once you've added the required columns, click **Review and create**. This will show you the SQL for the new table. If it looks correct, click **Create table**.
## Settings
The following settings are available within the Database studio:
* **Table rows count:** Displays the total number of rows in each table. This action performs a light scan of the table, which may slow down performance and increase billing costs, particularly for large tables or databases with many rows.
* **Expand subviews:** If a table contains a foreign key to another table, you can open the related data in a subview. This option keeps subviews open, allowing you to easily explore related records without navigating away.
* **Pagination type:** Choose how you want to view the results, **Limit offset** allows you to determine how many rows are shown per page, **Pages** shows the rows in batches of 50.
* **Flat schemas:** PostgreSQL only. Shows the database tables without grouping them by the schema.
* **Show bytea as:** PostgreSQL only. Choose to show the bytea data type as HEX or UTF8.
* **Editor keybindings:** Choose which keybinding profile you want to use for your keyboard shortcuts from VS Code, Vim, or Emacs.
## Report a bug
If you encounter an issue while using the Database studio, click Report a bug, you can then download the error context and report it to our [Support Team](/support/contact-support).
# TablePlus
Source: https://docs.sevalla.com/databases/manage-data/tableplus
Connect and manage databases using TablePlus.
There are many database tools for connecting to and managing your database. TablePlus allows you to manage all the [database types](/databases/get-started/add-a-database) you can host on Sevalla, so we're using it for this guide.
You can use any database client or tool ([including the command line](/databases/manage-data/tableplus)) that supports your database type. While some specifics, like navigation and field names, may vary between database tools, the fundamental concepts are the same.
If you haven't already, download and install TablePlus or the database client of your choice on your local machine.
## Connect to a Sevalla database
You can connect to your database with a single click from the database **Overview** page using **Open deeplink**.
Alternatively, within TablePlus, click **Create a new connection**, choose the database type, and click **Create**.
Complete the connection details in TablePlus with the information from your database's [**External connections**](/databases/connections) details in Sevalla, and click **Connect** once you've filled in the following:
* Host/Socket
* Port
* User (This is not required for Redis.)
* Password
* Database (This is not required for Redis.)
You are now connected to the Sevalla database, and you can use TablePlus to view and manage the database.
## Backup a database
We provide [automated and manual backups for databases](/databases/backups), but if you need to download a copy of your database, you can export it with TablePlus.
In TablePlus, click **File** > **Backup**, choose your connection and database, and click **Start backup**.
Enter a file name for the backup, choose where you want to save it, and click **Start backup**.
## Restore a database
You can [restore automatic or manual backups](/databases/backups#restore-a-backup) that are stored in Sevalla, but if you need to restore a backup that isn't in Sevalla, you can restore it with TablePlus.
When a database backup is restored, all changes to the database will be rolled back to the time the backup was created.
In TablePlus, click **File** > **Restore**, choose your connection and database, and click **Start restore**.
Browse to the file you want to restore and click **Start restore** again.
# Databases - Networking
Source: https://docs.sevalla.com/databases/networking
Connect to your databases using various clients and tools.
Networking allows you to communicate with your database using one of the following methods:
* An **external connection** involves an internet round-trip, making it significantly slower than internal communication. External connections are turned off by default. We recommend external connections if you are hosting only your database with us, but not your front end. To connect to the database using an external connection, you must [enable public access](/databases/connections#external-connections).
* An **internal connection** stays within our network and is thus much faster and more secure. We recommend this method if you host both your front-end and database with Application Hosting and Database Hosting services.
Internal connections are only available between applications and databases hosted with Application Hosting and Database Hosting services.
## Public networking
### External connection
To enable or disable external access to your database, select either **Enable** or **Disable**. If public access is enabled, you can use the connection details to [connect to your database](/databases/manage-data/tableplus) via the command line (CLI) or with a database tool.
Click **Open deeplink** to open your database within [TablePlus](https://docs.sevalla.com/databases/manage-data/tableplus).
### IP restrictions
IP restrictions allow you to restrict or block access to specific IP addresses or CIDR blocks. If an unauthorized user (IP address) attempts to access the database, they will receive a **403 – Forbidden error**.
To change your IP restriction settings, click **Update IP Restrictions** and choose from the following:
* **No IP restrictions:** Allows all connections to your database.
* **IP allowlist:** Allows connections only from the specified IP addresses. When you select this option, enter the IP addresses or CIDR notations that should have access to your database. To add multiple entries, click the plus icon after each one. There is no limit to the number of entries.
* **IP denylist:** Blocks connections from specified IP addresses. When you select this option, enter the IP addresses or CIDR notations you want to block from accessing your database. To add multiple entries, click the plus icon after each one. There is no limit to the number of entries.
To save the changes, click **Update IP restrictions**.
## Private networking
## Add internal connection
For the time being, internal connections are only supported between applications in the same region. If you're deploying an application and a database, you must choose the same region for both.
You can add internal connections from an application's **Networking** page or a database's **Networking** page. It doesn't matter where you start the process; the result will be the same.
To add a connection from a database to an application, click **Add internal connection**, and select the application you want to connect to.
To automatically populate an application's [environment variables](/applications/environment-variables) from the database connection details, select **Add environment variables to the application**. This automatically populates the environment variables from the database you're connecting to.
Select whether the variables will be available during runtime and/or the build process, and click **Add internal connection**.
Some applications may expect environment variables (keys) with different names. You can edit the names in the list before adding the connection or [**edit them later on the application's Settings page**](/applications/environment-variables).
### Ports
[The port](/applications/settings) for internal connections to an application can be defined when you add your application or within your application's **Networking** > **Update port**. The port for internal connections to a database is 3306 and cannot be changed.
For applications, Sevalla automatically sets the `PORT` environment variable. You do not need to define it yourself or hard-code it into the application. When an application is deployed, it is reachable on the internet on ports 80 and 443, and we route those ports to the container on the port defined by your application.
### Remove an internal connection
If you need to remove a connection, go to the Database's **Networking** page, and under **Connected applications**, click the delete (trash can) icon.
Click **Continue** to confirm and remove the connection between the application and the database.
## Change database password
You can change the database password for your internal and external connections. On the database **Overview** page, within **Manage password**, click **Change password** and enter a new password.
When you change the password, you must manually change the password in every client you use to connect to the database and update any other relevant [environment variables](/applications/environment-variables).
Passwords must be at least 8 characters and include at least one lowercase letter, one uppercase letter, a number, and one of the following special characters: ``, & * [ ] : ' $ ` "``
# Databases - Overview
Source: https://docs.sevalla.com/databases/overview
View an overview of Database Hosting in Sevalla.
With Sevalla’s Database Hosting, you can host any of the following database types on any one of our 25 data centers:
* **Redis** 5.0, 6.x, 7.x, and 8.x
* **MariaDB** 10.4, 10.5, 10.6, 10.11, 11.0, and 11.1
* **PostgreSQL** 9.6, 10, 11, 12, 13, 14, 15, 16, and 17
* **MySQL** 8.0 and 9.0
* **Valkey** 7.2
You can select different versions of these databases to suit your existing project.
It’s also possible to utilize a Dockerfile and persistent storage to [deploy other types of databases](/applications/build-options/dockerfile) on Application Hosting.
## Database studio
With the [Database Studio](/databases/manage-data/database-studio), you can manage your databases directly from the Sevalla UI. You can run queries, view data, and more without having to use an external tool or download your database.
## Scalability
You can easily scale up your database’s CPU, RAM, and disk space when needed. You can also increase your database disk space without increasing the RAM or CPU with the [database disk space add-on](/billing/database-pricing#database-disk-space-add-on).
## Internal connections
You can attach databases to applications or run databases by themselves. If you host both your application and database with Sevalla, you can set up an [internal connection](/databases/connections) between them to create a private network where everything is hosted on the same cluster. As this stays within our network, it is faster, more secure, and there is no internal bandwidth cost.
## Automatic backups
We provide automatic daily [backups for Database Hosting](/databases/backups) that are **stored for 7 days**. You can also manually create up to 5 manual backups, which are **stored for 14 days**.
## Pricing
Database Hosting pricing is usage-based, so you only pay for the resources your database uses, based on the following:
* The [database size](/databases/get-started/add-a-database) (database resource type) and [runtime](/databases/analytics)
* Egress bandwidth, if applicable
For information about how we calculate these, refer to [Database Pricing](/billing/database-pricing). To estimate your monthly costs before you deploy, use the [Sevalla pricing calculator](https://sevalla.com/pricing/calculator/).
# Databases - Settings
Source: https://docs.sevalla.com/databases/settings
Change your database configuration and preferences.
To access the database Settings, click **Settings** on the **Database** page.
## General
The **General** section shows you the display name and resources available for your database, including any [add-on storage](/billing/database-pricing#database-disk-space-add-on). To change your database’s display name or increase its size, click **Update details**, make your changes, and click **Update database details**.
If you’ve added any additional space with our database disk space add-on, you’ll need to follow the steps outlined here to [modify the database disk space add-on](/billing/database-pricing#database-disk-space-add-on).
You cannot decrease or downgrade the size of your database. The **Update details** flow only lets you increase the size, and this applies to any database type. If you need a smaller database, create a new database with the desired size (resource type) and move your data over - the easiest way is to [restore a backup](/databases/backups#restore-a-backup) to the new database, which works as long as it’s the same database type and in the same data center. Once the data has been moved, you can delete the old database. For the billing implications, see [Downgrade database](/billing/database-pricing#downgrade-database).
## Restart database
Restarting the database causes a brief downtime.
Restarting your database gracefully stops and restarts the database service. During the restart, existing connections are closed, and any active queries or uncommitted transactions are interrupted. Your stored data is not affected. The restart runs in the background and is usually completed within a few minutes.
## Suspend or Activate the database
Only Company Owners and Company Administrators can suspend or resume a database. For information about how to change a user’s access, refer to User Management.
Suspending your database stops your database from running without deleting it. This doesn’t change or remove anything in the database itself. Connections to the database remain in place but will not work while the database is suspended. You will not incur any costs for the database during the suspension.
Click **Suspend database** and confirm the suspension by clicking **Continue**.
When you’re ready to restart your database, click **Activate database** and confirm the restart by clicking **Continue**.
## Delete database
Only Company Owners and Company Administrators can delete a database. For information about how to change a user’s access, refer to User Management.
**Delete database** completely removes the database. If you delete the database, all of the data in it is destroyed.
# Databases - Troubleshooting
Source: https://docs.sevalla.com/databases/troubleshooting
Troubleshoot common database issues and errors.
When connecting to a database, if there's an issue with the connection details or the database itself, you may see one of these errors:
> Unable to connect to server
> Error 2013 (HY000): Lost connection to MySQL server
> Error 2002 (HY000): Can't connect to MySQL server
> MySQL server has gone away
If you see one of these or a similar error, check the following, and if the issue persists, [contact our Support team](/support/contact-support).
## Check connection details
To check your database [connection details](/databases/connections), head over to the **Info** page.
### Internal connection
If the connection is between an application and a database, and both are hosted on Sevalla, make sure they use the same [data center location](/service-information/data-center-locations) and are connected through an [internal connection](/databases/connections). Additionally, we recommend selecting the **Add environment variables to the application** checkbox when adding the connection. This automatically populates the [environment variables](/applications/environment-variables) in the application from the database connection details.
### External connection
If you are trying to connect your database to an external application or access your database with the [command line or a database client/tool](/databases/manage-data/tableplus), double-check your database's [external connection details](/databases/connections).
Your database's external connection details are different from the internal connection details.
## Suspend and Activate the database
If you've double-checked the connection details and an error persists, try [suspending and resuming the database](/databases/settings) on the database **Settings** page.
Click **Suspend database** and confirm the suspension by clicking **Continue**.
To restart your database, click **Activate database** and confirm the restart by clicking **Continue**.
# Docs - Sevalla®
Source: https://docs.sevalla.com/index
Cloud solution for web applications and databases.
## What can you do with Sevalla?
* **Deploy apps** from GitHub, GitLab, Bitbucket, or directly from Docker registry
* **Set up databases** like MySQL, PostgreSQL, MariaDB, or Redis with one click
* **Create pipelines** to manage environments (Dev, QA, Prod)
* **Preview environments** for every pull request
* **Deploy static sites** for free
## Get started
When you sign up to Sevalla, the first thing you need to do is enter your payment method and billing details, and then click **Complete setup**.
You can then use our quick step guides to:
* [Connect an AI agent](https://docs.sevalla.com/quick-starts/coding-agents/overview)
* [Deploy your own service](https://docs.sevalla.com/applications/get-started/add-an-application)
* [Deploy a database](https://docs.sevalla.com/databases/get-started/add-a-database)
* [Try our demo templates](https://docs.sevalla.com/templates/overview)
You can access these guides at any time from the **Help** menu by clicking **Get started guides**.
Here’s what you’ll probably want to check out first:
Connect your coding agent to the Sevalla MCP server to experience hands-free deployments.
Deploy Laravel, Python, Node.js, PHP, Ruby, Go, and more
Create PostgreSQL, MySQL, MariaDB or Redis
Build and deploy React, Angular, Vue or your HTML site for free
Store static assets in a bucket to save bandwidth
# Add a load balancer
Source: https://docs.sevalla.com/load-balancers/add-load-balancer
Follow this guide to add a load balancer in Sevalla.
To add a load balancer, log in to Sevalla, click **Load balancers**, and then click **Create load balancer**.
You can then choose the balancing mode from the following:
* **Default (Weighted):** Choose this option to control the proportion of traffic each destination receives. The traffic is distributed randomly across all destinations. This is ideal for canary deployments, A/B testing, and gradual migrations between services.
* **Geo:** Choose this option to automatically route users to the nearest destination based on their location. This reduces latency and improves performance for globally distributed applications.
Complete the following:
* **Name:** Add a name for the load balancer.
* **Project:** This option is only shown if your company already has at least one project. Select the project you’d like to add the load balancer to, or leave it blank to keep the load balancer at the company level instead of assigning it to a specific project.
Click **Create load balancer**.
You can change the balancing mode, name, and project at any time within the load balancer's **Settings**.
## Add a destination
Once you've created a load balancer, you can add the destinations you want to route users to or distribute the traffic across. You can add up to 20 destinations per load balancer.
To add a destination, click **Add destination** or the plus icon. You can then choose an application, a static site, another load balancer, or an external service.
If you choose an external service, you need to provide the URL, plus the longitude and latitude.
Once you've selected the destination, click **Create destination**.
When you've added your destinations, you can see the average response time for the past hour for each one.
To add a custom domain to your load balancer, refer to [Load balancers - Domains](https://docs.sevalla.com/load-balancers/domains).
## Disable, enable, or remove a destination
You can enable or disable each load balancer individually without removing it from the configuration, or you can completely remove a destination from the load balancer.
To disable, enable, or remove a destination, click the ellipsis (three dots) on the destination and choose the required option.
## Remove the load balancer
To completely remove the load balancer, click the trash can icon and confirm the deletion by clicking **Continue**.
# Load balancers - Analytics
Source: https://docs.sevalla.com/load-balancers/analytics
View detailed analytics for your load balancers.
Load balancer analytics give you clear visibility into how your traffic is performing and where it’s coming from. These insights help you monitor performance, troubleshoot issues faster, and make informed scaling decisions.
When viewing the analytics, you can choose to see data for the past 1 hour, 6 hours, 12 hours, 1 day, 2 days, 4 days, 7 days, 14 days, or 30 days, or select a specific date and time period.
When you hover over a chart, a reference line appears; you can click and drag this reference line to zoom into a specific time period.
You can filter the charts using **Add filter**. This filters all of the charts on the page. The following options are available:
* Destination
* Source IP
* Country
* Device type
* HTTP method
* Path
* User agent
* HTTP version
* Status code
To view the analytics, click **Load balancers** > ***name*** > **Overview** and scroll down to the **Analytics** for that specific load balancer.
#### Requests volume by country
The Requests volume by country chart shows the number of requests, ranked by the country from which they originated. You can zoom in and out of the map, and hover over a country to see the exact number of requests from that location. You can also filter the chart to include or exclude specific countries.
#### Response time
The Response time chart shows the average response time for all HTTP requests for the time period selected.
#### Status codes
The Status codes chart displays the total number of each status code returned for requests. This is useful for analyzing your site to identify when requests return codes other than 200.
#### Requests per minute
The Requests per minute chart shows the average requests per minute (RPM) of all HTTP requests for the time period selected.
# Load balancers - Domains
Source: https://docs.sevalla.com/load-balancers/domains
Add and manage custom domains for your load balancers.
When you add a load balancer, it's automatically assigned a free sevalla.net domain as the primary domain.
You can add your custom domain on the **Domains** page. Every custom domain you add automatically includes a free SSL certificate. The temporary sevalla.net domains are automatically covered by the wildcard certificate of sevalla.net domain. (\*.sevalla.net). If you want to add a custom SSL certificate, please [contact our Support Team](https://docs.sevalla.com/support/contact-support), who can manually upload this for you.
## Add domain
In [Sevalla,](https://app.sevalla.com/) go to **Load balancers** > ***name*** > **Domains**.
Click **Add custom domain** and enter your domain name. If you want to cover all subdomains, select **Wildcard** and then click **Add custom domain**.
If you add your domain without the wildcard subdomain, you should also consider adding the www version of the domain without the wildcard to ensure both versions are correctly configured.
## Verify domain
To verify your domain, you need to add the TXT record and CNAME record shown to your domain's DNS records. Some DNS providers, such as [Namecheap](https://www.namecheap.com/), [Spaceship](https://www.spaceship.com/), and [Squarespace](https://www.squarespace.com/) need the short version of DNS record names. Sevalla automatically provides both the full and short versions of each record, so you can use whichever format your DNS provider needs.
**TXT record**
The TXT record allows Cloudflare to verify that you own the domain and are authorized to use their services for that domain. Once the domain is fully validated, you can remove this record from your DNS if necessary.
* Name: `_cf-custom-hostname`
* Value: Unique UUID value from Sevalla (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
**CNAME record**
Sevalla uses this DNS entry to update the domain with the necessary tokens for your SSL certificate. As long as this record exists in your DNS, you won't need to manually renew your SSL certificate; Sevalla manages it for you. We don't recommend removing this DNS entry, as you will need to re-add it each time the SSL certificate requires renewal.
* Name: `_acme-challenge`
* Value: `example.com.[unique verification token].dcv.cloudflare.com`
Allow 5-10 minutes for DNS to propagate. If propagation doesn't occur as expected, you can use a DNS lookup tool, such as [dnschecker.org](https://dnschecker.org/) or [mxtoolbox.com](https://mxtoolbox.com/), to verify if the record is resolving correctly.
## Point domain
Once your domain is successfully verified, you can point it by adding the required A records to your domain's DNS settings.
Some DNS providers, such as [Namecheap](https://www.namecheap.com/), [Spaceship](https://www.spaceship.com/), and [Squarespace](https://www.squarespace.com/), need the short version of DNS record names. Sevalla automatically provides both the full and short versions of each record, so you can use whichever format your DNS provider needs.
If you select the **Wildcard** option, an additional A record for `*.yourdomain.com` appears to add to your domain's DNS settings, which ensures all subdomains are covered.
When the domain is successfully pointed, a success message appears.
### Point WWW domain
We recommend that you point the www version of your domain to Sevalla (if you haven't already). To do so, add the www version of the domain to Sevalla and repeat the steps to verify and point the subdomain.
## Change your primary domain
In the domains list, locate the domain you want to be the primary domain, click the kebab (three-dot) menu, and click **Make primary domain**. Verify that the correct domain is selected, then click **Continue**.
## Troubleshoot domain issues
Most domain problems happen during verification or pointing, and they usually come down to a conflicting or mis-entered DNS record. Work through the checks below in order.
### Domain won't verify
If your domain stays unverified after you've added the TXT and CNAME records, check the following:
* **Remove any existing A or CNAME record on the root domain.** If your domain already has an A or CNAME record (for example, pointing to a previous host), Cloudflare tries to verify ownership through that record, and verification fails. Remove the old A or CNAME record before verifying, then add the records Sevalla provides.
* **Confirm the `_acme-challenge` record is a CNAME, not a TXT.** The `_acme-challenge` value Sevalla provides (ending in `dcv.cloudflare.com`) must be added as a **CNAME** record. A common mistake is pasting it into a TXT record, which prevents the SSL certificate from being issued.
* **Disable the Cloudflare proxy on the verification records.** If you use Cloudflare as your DNS provider, set the verification records to **DNS only** (grey cloud). Proxied (orange cloud) records don't resolve publicly, so verification can't complete. You can re-enable the proxy on your A or CNAME records after the domain is active.
* **Remove conflicting or stale records.** If you previously added and removed this domain in Sevalla, an old `_cf-custom-hostname` TXT value may still be in your DNS. Delete any outdated `_cf-custom-hostname` or `_acme-challenge` records and re-add the exact values shown in Sevalla.
* **Confirm the value matches exactly.** Copy the value directly from Sevalla. A trailing space, a missing character, or a wrong record name causes verification to fail.
* **Check the Time-to-Live (TTL) setting.** This controls how long internet providers and other services remember your DNS settings before checking for updates. It is usually set to Auto or 5 minutes, but if it has been changed to a longer period, DNS propagation can take longer to take effect.
Allow 5-10 minutes after each change for DNS to propagate. Use [dnschecker.org](https://dnschecker.org/) or [mxtoolbox.com](https://mxtoolbox.com/) to confirm a record resolves before assuming it's wrong.
### SSL certificate isn't issued
Sevalla issues and renews your SSL certificate automatically once the domain is verified. If the certificate stays pending:
* Keep the `_acme-challenge` CNAME record in place. Removing it stops Sevalla from renewing your certificate, and you would need to re-add it.
* Check for a CAA record conflict, described in **Fix domain error** below.
### Fix domain error (CAA record conflict)
During the domain verification process, if a **Fix domain error** button appears next to the domain, this means a CAA record conflict is occurring.
A CAA record is an optional DNS record that lets you specify which certificate authorities (CAs) are allowed to issue SSL certificates for your domain. If a domain has no CAA records, any CA can generate an SSL certificate for it if requested. If a domain has a CAA record, only the CA(s) specified in the CA record can generate an SSL certificate for the domain.
To resolve this error, click the **Fix domain error** button and update the CAA record as indicated in the modal/pop-up. Alternatively, if you do not need a CAA record on your domain, you can remove the CAA record.
### Domain verified, but the load balancer doesn't respond
If the domain verifies but doesn't route traffic to your load balancer:
* Confirm the A record (or CNAME) matches the exact value shown on the **Point domain** step in Sevalla. If you reused an old record, update it.
* If you use the Cloudflare proxy, make sure it's enabled only on the A or CNAME records that point to Sevalla, not on the verification records.
* For wildcard domains, confirm you also added the `*.yourdomain.com` A record.
### Check your DNS records
You can see what's actually published for your domain with these commands:
```bash theme={null}
dig +short yourdomain.com A # Existing A record (remove before verifying)
dig +short yourdomain.com CNAME # Existing CNAME (remove before verifying)
dig +short _cf-custom-hostname.yourdomain.com TXT # Ownership TXT - must match the value in Sevalla
dig +short _acme-challenge.yourdomain.com CNAME # SSL validation CNAME
```
If the published values don't match what Sevalla shows, update your DNS records and wait for propagation. If they match and the domain still won't verify, [contact our Support Team](https://docs.sevalla.com/support/contact-support).
# Load balancers - Overview
Source: https://docs.sevalla.com/load-balancers/overview
Overview of Sevalla's load balancers.
Sevalla’s load balancers give you precise, flexible control over how traffic is distributed across your services.
Load balancers run on Cloudflare’s edge network, and requests are routed as close as possible to your users. This allows for faster response times, smarter routing decisions, and improved reliability without requiring you to manage additional infrastructure.
You can route traffic to:
* Applications
* Static sites
* Object storage buckets
* External URLs
* Even other load balancers
Each load balancer supports up to 20 destinations.
The following balancing modes are available:
* **Weighted:** Control what proportion of traffic each destination receives. This is ideal for canary deployments, A/B testing, and gradual migrations between services.
* **Geographic:** Automatically route users to the nearest destination based on their location. This reduces latency and improves performance for globally distributed applications by ensuring users are served from the most optimal region available.
Each destination can be enabled or disabled individually without being removed from the configuration. Traffic weights can be adjusted at any time, allowing you to shift traffic instantly without redeploying or reconfiguring infrastructure.
Custom domains are fully supported and include automatic SSL provisioning. You’ll also receive an auto-generated Sevalla domain immediately upon creation, so you can start routing traffic right away.
By combining edge-based routing, flexible balancing modes, and simple operational controls, Sevalla makes it straightforward to build resilient, multi-region architectures and manage traffic across services, without relying on external tooling or complex infrastructure setups.
## Pricing
Each load balancer has a base fee of \$40 per month.
In addition to the base fee, outbound traffic (egress) from the load balancer to end users is billed based on bandwidth usage. We charge strictly per byte at a rate of \$0.0000000001 per byte (\$0.1 per GB).
There is no rounding up, and you are only charged for the exact amount of bandwidth consumed.
For detailed information about your load balancer costs, the **Usage** page within **Settings** provides complete visibility into your resource consumption and costs for both the current and previous billing periods across all your services.
# Add an object storage
Source: https://docs.sevalla.com/object-storage/add-an-object-storage
Add a new object storage bucket to your account.
Object storage lets you store any type of digital file for \$0.02 per GB. You can access your files using an S3-compatible API, an SDK, or the AWS CLI, making it easy to integrate with various applications and workflows.
If you currently have a bucket with AWS or GCP and would like to transfer your files from this bucket to Sevalla, please [contact our Support Team](/support/contact-support/).
To add object storage within Sevalla, click **Object storage** and then **Create object storage**.
Enter a name and choose a location. These locations are the available R2 locations, which are different from data center locations. By default, Sevalla selects a location in the closest available region.
The **Project** option is only shown if your company already has at least one project. Select the project you’d like to add the object storage to, or leave it blank to keep the object storage at the company level instead of assigning it to a specific project.
Once you've selected the required options, click **Create object storage**.
Once you've created the object storage, you can upload your files.
## Add files
Within the object storage instance, click **Upload**.
You can upload files by simply dragging and dropping them or by selecting individual files or an entire folder containing the files you want to upload.
## Download files
You can download any file within the object storage at any time. To do so, click the ellipsis (three dots) next to the file you want to download and click **Download**.
## Delete files
To delete a file, click the ellipsis (three dots) next to the file you want to remove and click **Delete**. Once an object is deleted, it cannot be recovered.
You can also delete multiple files at once. Select the files you want to delete and click **Delete files**.
# Connect to object storage
Source: https://docs.sevalla.com/object-storage/connect-to-object-storage
Learn how to connect to your object storage buckets.
You can connect to your object storage using an S3-compatible API, an SDK, or the AWS CLI. Below are some examples of commands you can use with these methods. For a full list of compatible commands, refer to [S3 API compatibility](https://developers.cloudflare.com/r2/api/s3/api/).
If you currently have a bucket with AWS or GCP and would like to transfer your files from this bucket to Sevalla, please [contact our Support Team](/support/contact-support/).
## AWS CLI
### Configure your bucket
```
aws configure set aws_access_key_id YOUR_ACCESS_KEY
aws configure set aws_secret_access_key YOUR_SECRET_KEY
aws configure set default.s3.signature_version s3v4
aws configure set default.s3.endpoint_url YOUR_ENDPOINT_URL
```
### Generate a pre-signed URL
```
aws s3 presign s3://YOUR_BUCKET_NAME/FILENAME --expires-in 3600 --endpoint-url YOUR_ENDPOINT_URL
```
### Upload a file
```
aws s3 cp LOCAL_FILENAME s3://YOUR_BUCKET_NAME/ --endpoint-url YOUR_ENDPOINT_URL
```
### Download a file
```
aws s3 cp s3://YOUR_BUCKET_NAME/REMOTE_FILENAME DOWNLOADED_FILENAME --endpoint-url YOUR_ENDPOINT_URL
```
### List your bucket objects
```
aws s3 ls s3://YOUR_BUCKET_NAME/ --endpoint-url YOUR_ENDPOINT_URL
```
## Boto3 (Python SDK)
Install Boto3 if you haven’t already:
```
pip3 install boto3
```
Enter Python interactive mode:
```
python3
```
### Connect to your object storage
```
import boto3
from botocore.client import Config
# Set up R2 connection
s3 = boto3.client(
"s3",
endpoint_url="YOUR_ENDPOINT_URL",
aws_access_key_id="YOUR_ACCESS_KEY",
aws_secret_access_key="YOUR_SECRET_KEY",
config=Config(signature_version="s3v4"),
)
```
### Generate a pre-signed URL
```
presigned_url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": "YOUR_BUCKET_NAME", "Key": "REMOTE_FILE_NAME"}, # Replace values
ExpiresIn=3600, # Expiration time in seconds (e.g., 1 hour)
)
print("Pre-signed URL:", presigned_url) # Ensure this prints
```
### Upload a file
```
s3.upload_file("LOCAL_FILENAME", "YOUR_BUCKET_NAME", "UPLOADED_FILENAME")
```
### Download a file
```
s3.download_file("YOUR_BUCKET_NAME", "REMOTE_FILENAME", "DOWNLOADED_FILENAME")
```
### List your bucket objects
```
response = s3.list_objects_v2(Bucket="your-bucket-name")
print(response) # See what files exist
```
# Object storage infrastructure
Source: https://docs.sevalla.com/object-storage/infrastructure
Get details about the infrastructure behind Sevalla's object storage.
Sevalla's object storage is built on Cloudflare R2 and provides secure access to files through an S3-compatible API. The following outlines the storage architecture and access methods in detail.
## Sevalla dashboard
Use the Sevalla dashboard to easily create and manage your object storage buckets. Once your bucket is set up, you can upload, download, and organize files directly through the web interface. Within the dashboard, you can also adjust your bucket settings and access controls.
The maximum file size for uploads via the Sevalla dashboard is 300MB, anything larger than this can be uploaded via CLI or SDK.
## S3-compatible CLI
You can interact with your Sevalla object storage bucket using any S3-compatible command-line interface, such as the AWS CLI or s5cmd. After configuring your CLI with your Sevalla access credentials and endpoint, you can perform operations like listing, uploading, downloading, and deleting files programmatically or via scripts.
## SDK
Sevalla's object storage supports integration with a wide range of AWS S3-compatible SDKs, enabling developers to programmatically interact with their object storage buckets. Whether you're working in Python (boto3), JavaScript (AWS SDK), Go, or other languages, you can use familiar S3 API calls to upload, retrieve, and manage files.
## Cloudflare
When you upload a file to your Sevalla bucket, it is securely stored in Cloudflare R2 within the region you selected during bucket creation. Cloudflare R2 is a globally distributed object storage platform engineered for high durability, low latency, and cost efficiency.
By leveraging Cloudflare R2 through Sevalla, you benefit from scalable and resilient storage, simplified access controls, transparent pricing, and enhanced regional performance.
## Cloudflare edge
Files stored in your Sevalla bucket are served through Cloudflare’s global edge network, which spans hundreds of data centers worldwide. This edge infrastructure ensures fast, reliable access to your content by delivering it from locations closest to your users, while maintaining strong data consistency and high availability.
You can optionally enable public access to your bucket. When enabled, Sevalla provides a public URL for each file, allowing it to be served directly via Cloudflare's edge. This is especially useful for media assets, downloads, or static content intended for public consumption.
# Object storage - Overview
Source: https://docs.sevalla.com/object-storage/overview
Overview of Sevalla's object storage.
Sevalla's object storage, powered by Cloudflare R2, provides a flexible bucket system for storing any type of digital file, including photos, videos, documents, and more. All files are stored privately and can be accessed securely using an S3-compatible API. There are no limits on the number of files you can store, and storage is priced at \$0.02 per GB.
You can create a separate object storage bucket for each project, and the number of storage buckets you can set up is unlimited.
Sevalla's user management allows you to create and manage users directly within each object storage bucket, giving you full control over who can access each storage environment.
If you currently have a bucket with AWS or GCP and would like to transfer your files from this bucket to Sevalla, please [contact our Support Team](/support/contact-support/).
For detailed information about your object storage costs, the **Usage** page within **Company settings** provides complete visibility into your resource consumption and costs for both the current and previous billing periods across all your services.
# Object storage - Settings
Source: https://docs.sevalla.com/object-storage/settings
Configure object storage settings and access controls.
The object storage settings show the details required to access your files via an S3-compatible API. You can also enable public access and delete the object storage.
## Details
The object storage details contains the information you need to connect to your storage bucket via an S3-compatible API.
### Roll secret
To rotate the access and secret keys for your object storage bucket without taking clients offline, click **Roll secret**. Choose when you want the old keys to expire, and click **Continue**.
## CORS Policy
[Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) is a browser security feature that controls how web resources can be requested from a different origin (domain, protocol, or port) than the one the web page was loaded from. A CORS policy is a set of rules defined by a server to specify which external origins (domains, ports, or protocols) are allowed to access its resources via cross-origin HTTP requests. To set up a CORS Policy on your object storage bucket, click **Create rule**.
Complete the policy as follows:
* **Allowed methods:** This defines the value of the `Access-Control-Allow-Methods` header that R2 sets when a browser requests objects from your bucket. You can select any of the following HTTP methods: `GET`, `PUT`, `POST`, `DELETE`, and `HEAD`.
* **Allowed origin:** Specifies the value of the `Access-Control-Allow-Origin` header that R2 sets when a browser requests objects from your bucket. This is the origin from which the request is being made; for example, if the site `www.example.com` needs access to your bucket, enter `www.example.com` as the allowed origin.
* **Allowed header:** Defines the value for the `Access-Control-Allow-Headers` header that R2 sets when a browser sends cross-origin requests to your bucket. If your requests include custom headers, such as `x-user-id` or `x-auth-token`, you need to add them here so the browser permits them.
If a network request is still blocked by your browser, look at the AllowedOrigins, AllowedMethods, and AllowedHeaders of the network request and ensure the CORS policy includes the correct information.
## Public access
By default, the object storage files are private. When you enable Public Access, the bucket is assigned a unique subdomain under **sevalla.storage** (e.g., my-bucket.sevalla.storage).
## Cache
Objects served from your bucket are cached on our global CDN. If freshly uploaded or replaced objects aren't being served yet, you can clear the cache yourself instead of waiting for it to expire.
To clear the cache, click **Purge cache**. This purges the CDN cache for your bucket, so the latest version of your objects is served immediately. The purge takes effect right away, and you'll get a confirmation once the cache is cleared.
Anyone with update access to the object storage can purge the cache.
## Delete object storage
Deleting your object storage bucket permanently removes the bucket, all stored objects, and any associated credentials. Once deleted, the bucket and its contents cannot be recovered.
If you no longer need the object storage bucket, click **Delete object storage** and confirm the deletion.
# Projects - Overview
Source: https://docs.sevalla.com/projects/overview
View an overview of Projects in Sevalla.
Projects let you group all of your Sevalla services into a single workspace, making it easy to manage your project’s resources in one place. You can add applications, databases, object storage, and static sites to a project, giving you a simple, organized way to navigate and manage everything together.
Company-level users can fully manage projects. Project developers can add new services to a project, but they cannot add existing services or remove services.
## Create a project
To create a new project, within **Projects**, click **Create project**. Give the project a name and click **Create project**.
## Add services to a project
Once you've created your project, you can add applications, pipelines, databases, static sites, and object storage to the project.
Select the project you want to add services to, click **Create or add service**, and you can then choose to add an existing service or create a new service to add to the project.
Project Developers can only add new services to a project; they cannot add existing services.
If you choose to add an existing service, choose the service type, select the required services, and click **Add services**.
If you want to add a new service, select one of the following options:
* [Create application](https://docs.sevalla.com/applications/get-started/add-an-application)
* [Create pipeline](https://docs.sevalla.com/applications/get-started/pipelines#add-a-pipeline)
* [Create database](https://docs.sevalla.com/databases/get-started/add-a-database)
* [Create static site](https://docs.sevalla.com/static-sites/get-started/add-a-static-site)
* [Create object storage](https://docs.sevalla.com/object-storage/add-an-object-storage)
Once you create the new service, it is automatically added to the project.
## Remove services from a project
Project developers cannot remove services from a project.
To remove a service from a project, click the ellipsis (three dots) and click **Remove from project**.
This only removes the service from a project. If you want to completely remove the service, refer to one of the following:
* [Delete an application](https://docs.sevalla.com/applications/settings#delete-app)
* [Delete a pipeline](https://docs.sevalla.com/applications/get-started/pipelines#delete-a-pipeline)
* [Delete a database](https://docs.sevalla.com/databases/settings#delete-database)
* [Delete a static site](https://docs.sevalla.com/static-sites/settings#danger-zone)
* [Delete object storage](https://docs.sevalla.com/object-storage/settings#delete-object-storage)
# Projects - Settings
Source: https://docs.sevalla.com/projects/settings
Change your project's settings and preferences.
On your project's **Settings** page, you can find details about your project, update the project name, and suspend or delete it.
## General
### Details
This section shows the project display name, name, and ID. To change the display name, click **Update display name**, enter a new name, and click **Update display name**.
## Danger zone
Only Company Owners and Company Administrators can suspend or delete a project. For information about how to change a user's access, refer to User Management.
### Suspend services
There may be times when you need to stop all of the services within your project without deleting the project. This can be useful if you need to troubleshoot issues or test services within the project.
Suspending the project doesn't change or remove anything from it. Connections remain in place but will not work while the project is suspended. You will not incur any costs for the services within the project during the suspension.
Click **Suspend services** and confirm the suspension by clicking **Continue**. This suspends all applications and databases within the project.
To resume the services, you must activate them within each individual service. Refer to one of the following:
* [Suspend or Activate the application](https://docs.sevalla.com/applications/settings#suspend-or-activate-app)
* [Suspend or Activate the database](https://docs.sevalla.com/databases/settings#suspend-or-activate-the-database)
### Delete project
If you no longer need the project, click **Delete project** and click **Continue** to remove it completely.
Deleting the project does not remove the services within it. These services are still accessible at the company level, and you will still incur costs for these services. If you need to delete the services, refer to one of the following:
* [Delete an application](https://docs.sevalla.com/applications/settings#delete-app)
* [Delete a pipeline](https://docs.sevalla.com/applications/get-started/pipelines#delete-a-pipeline)
* [Delete a database](https://docs.sevalla.com/databases/settings#delete-database)
* [Delete a static site](https://docs.sevalla.com/static-sites/settings#danger-zone)
* [Delete object storage](https://docs.sevalla.com/object-storage/settings#delete-object-storage)
# Project Usage
Source: https://docs.sevalla.com/projects/usage
View the spending usage of your project broken down by service.
The Project Usage page provides a clear overview of your project’s total cost, along with a detailed breakdown by service. To help you see where your spending is concentrated, for each service, you can see:
* Its individual cost.
* The percentage it contributes to the overall project total.
You can view the chart for the current billing and previous billing periods.
Hover over any of the bars within the chart to see the breakdown of costs for that day.
# Claude Code
Source: https://docs.sevalla.com/quick-starts/coding-agents/claude-code
Connect Claude Code to the Sevalla MCP server with OAuth or API key authentication.
Use this guide to connect Claude Code to the Sevalla MCP server at `https://mcp.sevalla.com/mcp`.
After setup, Claude Code can use Sevalla MCP tools like `search` and `execute` directly from chat.
Check out Sevalla's MCP in action with Claude Code:
## Quick setup (CLI + OAuth)
OAuth is the recommended authentication method.
1. Add the Sevalla MCP server:
```bash theme={null}
claude mcp add --transport http sevalla https://mcp.sevalla.com/mcp
```
2. Open Claude Code and run:
```text theme={null}
/mcp
```
3. Select `sevalla` and complete the browser login flow with your Sevalla account.
4. Run `claude mcp list` to confirm the server is configured.
## Manual configuration (`.mcp.json`)
You can define Sevalla manually in `.mcp.json` (project-shared) or in `~/.claude.json` (personal).
```json theme={null}
{
"mcpServers": {
"sevalla": {
"type": "http",
"url": "https://mcp.sevalla.com/mcp"
}
}
}
```
If you need API key auth instead of OAuth, add an authorization header:
```json theme={null}
{
"mcpServers": {
"sevalla": {
"type": "http",
"url": "https://mcp.sevalla.com/mcp",
"headers": {
"Authorization": "Bearer ${SEVALLA_API_KEY}"
}
}
}
}
```
Do not commit real API keys to Git. Use environment variables.
## Configuration scope
* `local` (default): private to the current project context.
* `project`: shared via `.mcp.json` in the repository.
* `user`: available to your user account across projects.
Use `--scope project` for team-shared setups and `--scope user` for personal cross-project setups.
## Uninstall
1. Within Claude Code run:
```text theme={null}
claude mcp remove sevalla
```
2. Clear the stored OAuth token. In Claude Code run `/mcp`, select Sevalla, and choose Clear authentication.
If the server was added at a non-default scope, specify it explicitly:
```text theme={null}
claude mcp remove --scope user sevalla
claude mcp remove --scope project sevalla
```
## Reference
* Sevalla MCP endpoint: `https://mcp.sevalla.com/mcp`
* Sevalla MCP repository: [github.com/sevalla-hosting/mcp](https://github.com/sevalla-hosting/mcp)
# Codex
Source: https://docs.sevalla.com/quick-starts/coding-agents/codex
Connect Codex (OpenAI) to the Sevalla MCP server with OAuth or API key authentication.
Use this guide to connect Codex to the Sevalla MCP server at `https://mcp.sevalla.com/mcp`.
After setup, Codex can use Sevalla MCP tools such as `search` and `execute`.
## Quick setup (CLI + OAuth)
OAuth is the recommended authentication method.
1. Add the remote MCP server:
```bash theme={null}
codex mcp add sevalla --url https://mcp.sevalla.com/mcp
```
2. Authenticate with OAuth:
```bash theme={null}
codex mcp login sevalla
```
3. Verify configuration:
```bash theme={null}
codex mcp list
```
## Manual configuration (`config.toml`)
Codex uses TOML (not JSON) for MCP configuration.
You can configure MCP servers in:
* `~/.codex/config.toml` (user scope)
* `.codex/config.toml` (project scope, trusted projects only)
```toml theme={null}
[mcp_servers.sevalla]
url = "https://mcp.sevalla.com/mcp"
```
If you need API key auth instead of OAuth, pass an auth header from an environment variable:
```toml theme={null}
[mcp_servers.sevalla]
url = "https://mcp.sevalla.com/mcp"
env_http_headers = { Authorization = "SEVALLA_AUTH_HEADER" }
```
```bash theme={null}
export SEVALLA_AUTH_HEADER="Bearer "
```
Do not hardcode secrets in `config.toml`. Keep API keys in environment variables.
## Configuration scope
* User scope: `~/.codex/config.toml`, available in all projects.
* Project scope: `.codex/config.toml`, loaded only when the project is trusted.
Project settings override user settings for matching keys.
## Uninstall
Run the following:
```bash theme={null}
codex mcp remove sevalla
```
## Reference
* Sevalla MCP endpoint: `https://mcp.sevalla.com/mcp`
* Sevalla MCP repository: [github.com/sevalla-hosting/mcp](https://github.com/sevalla-hosting/mcp)
# Cursor
Source: https://docs.sevalla.com/quick-starts/coding-agents/cursor
Learn how to give Cursor full access to the Sevalla PaaS API.
[Cursor](https://cursor.com/) is an AI-powered coding assistant designed to help developers write, edit, and understand code more efficiently. It integrates directly with your development environment and uses natural language prompts to streamline coding tasks.
Use this guide to connect Cursor to the Sevalla MCP server at `https://mcp.sevalla.com/mcp`.
After setup, Cursor Agent can use Sevalla MCP tools like `search` and `execute`.
## Quick setup (Cursor UI + OAuth)
OAuth is the recommended authentication method.
1. Click the install button above and allow Cursor to open, or go to MCP configuration.
2. Complete the MCP server install flow in Cursor.
3. If prompted, confirm the server values:
* Name: `sevalla`
* URL: `https://mcp.sevalla.com/mcp`
4. Complete the OAuth browser flow when prompted.
5. Confirm the server is enabled in your MCP tools list.
## Manual configuration (`mcp.json`)
Cursor supports both project and global MCP config files:
* Project scope: `.cursor/mcp.json`
* Global scope: `~/.cursor/mcp.json`
```json theme={null}
{
"mcpServers": {
"sevalla": {
"url": "https://mcp.sevalla.com/mcp"
}
}
}
```
If you need API key auth instead of OAuth, add headers:
```json theme={null}
{
"mcpServers": {
"sevalla": {
"url": "https://mcp.sevalla.com/mcp",
"headers": {
"Authorization": "Bearer ${env:SEVALLA_API_KEY}"
}
}
}
}
```
## Configuration scope
* Use `.cursor/mcp.json` when the server config should live with the project.
* Use `~/.cursor/mcp.json` when you want the server available across all projects.
When both are present, keep shared project defaults in `.cursor/mcp.json` and personal overrides in `~/.cursor/mcp.json`.
## Uninstall
1. Delete the `sevalla` entry from either `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global).
2. Clear cached OAuth tokens, run:
```json theme={null}
rm -rf ~/.mcp-auth
```
## Reference
* Sevalla MCP endpoint: `https://mcp.sevalla.com/mcp`
* Sevalla MCP repository: [github.com/sevalla-hosting/mcp](https://github.com/sevalla-hosting/mcp)
# OpenCode
Source: https://docs.sevalla.com/quick-starts/coding-agents/opencode
Connect OpenCode to the Sevalla MCP server using OAuth or API key authentication.
Use this guide to connect OpenCode to the Sevalla MCP server at `https://mcp.sevalla.com/mcp`.
After setup, OpenCode can call Sevalla MCP tools like `search` and `execute` from the same session.
## Quick setup (CLI + OAuth)
OAuth is the recommended authentication method.
1. Add a remote MCP server from the OpenCode CLI:
```bash theme={null}
opencode mcp add
```
2. In the interactive prompt, choose:
* Type: `remote`
* Name: `sevalla`
* URL: `https://mcp.sevalla.com/mcp`
3. Authenticate:
```bash theme={null}
opencode mcp auth sevalla
```
4. Verify the server status:
```bash theme={null}
opencode mcp list
```
## Manual configuration (`opencode.json`)
You can configure MCP servers in:
* `opencode.json` in your project root (project scope)
* `~/.config/opencode/opencode.json` (global scope)
```json theme={null}
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"sevalla": {
"type": "remote",
"url": "https://mcp.sevalla.com/mcp",
"enabled": true
}
}
}
```
If you need API key auth instead of OAuth:
```json theme={null}
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"sevalla": {
"type": "remote",
"url": "https://mcp.sevalla.com/mcp",
"oauth": false,
"headers": {
"Authorization": "Bearer {env:SEVALLA_API_KEY}"
}
}
}
}
```
## Configuration scope
OpenCode merges config layers. Project config overrides conflicting values from global config.
* Global scope: `~/.config/opencode/opencode.json`
* Project scope: `opencode.json`
## Uninstall
1. Run:
```bash theme={null}
opencode mcp logout sevalla
```
2. Delete the `sevalla` entry from `opencode.json` in your project root.
## Reference
* Sevalla MCP endpoint: `https://mcp.sevalla.com/mcp`
* Sevalla MCP repository: [github.com/sevalla-hosting/mcp](https://github.com/sevalla-hosting/mcp)
# Get started with coding agents
Source: https://docs.sevalla.com/quick-starts/coding-agents/overview
Learn how to give AI agents full access to the Sevalla PaaS API using Sevalla's MCP server.
Sevalla’s Model Context Protocol (MCP) server enables AI agents to interact with the Sevalla platform programmatically through natural language. Instead of relying on traditional SDKs or pre-built integrations, AI agents can dynamically discover and call the Sevalla API endpoints as needed.
The MCP server provides a secure execution environment where AI-generated JavaScript runs inside a sandboxed V8 isolate, ensuring that API calls can be performed safely without exposing your infrastructure or credentials.
At its core, the MCP server exposes two tools:
* `search` – Allows the AI agent to query the Sevalla OpenAPI specification to discover available endpoints, parameters, and schemas.
* `execute` – Runs JavaScript inside the secure V8 sandbox, enabling the agent to construct and execute API requests dynamically.
This architecture follows the [Code Mode MCP pattern](https://blog.cloudflare.com/code-mode/), inspired by Cloudflare's solution. Rather than registering a separate tool for every API endpoint, the pattern provides just two general-purpose tools: one for exploring the API specification and another for executing code against it. This dramatically reduces complexity while giving AI agents full flexibility to work with large APIs.
With this setup, any MCP-compatible client can manage the Sevalla infrastructure through conversation. The AI agent automatically discovers available API endpoints and generates the necessary calls in real time—without requiring SDKs, boilerplate code, or hundreds of predefined tools.
Sevalla’s hosted MCP server can be connected directly to popular MCP-enabled development environments, including:
* [Claude Code](https://docs.sevalla.com/quick-starts/coding-agents/claude-code)
* [Codex](https://docs.sevalla.com/quick-starts/coding-agents/codex)
* [Cursor](https://docs.sevalla.com/quick-starts/coding-agents/cursor)
* [Windsurf](https://docs.sevalla.com/quick-starts/coding-agents/windsurf)
* [OpenCode](https://docs.sevalla.com/quick-starts/coding-agents/opencode)
Authentication is handled through OAuth, so you don’t need to embed API keys in configuration files. Once connected, your AI agent can safely explore the API and perform actions on your behalf, allowing you to manage applications, services, and infrastructure through a conversational interface.
Check out Sevalla's MCP in action with Claude Code:
## Quick start
Connect your MCP client to the hosted server at [https://mcp.sevalla.com](https://mcp.sevalla.com/).
Authentication is handled automatically via OAuth. When your client connects, a browser window opens so you can sign in to your Sevalla account and authorize the connection. No API keys or credentials need to be added to your configuration.
For details on how to connect using a specific AI client, refer to one of the following:
* [Claude Code](https://docs.sevalla.com/quick-starts/coding-agents/claude-code)
* [Codex](https://docs.sevalla.com/quick-starts/coding-agents/codex)
* [Cursor](https://docs.sevalla.com/quick-starts/coding-agents/cursor)
* [Windsurf](https://docs.sevalla.com/quick-starts/coding-agents/windsurf)
* [OpenCode](https://docs.sevalla.com/quick-starts/coding-agents/opencode)
## Uninstall the Sevalla MCP server
To fully remove the Sevalla MCP server, delete the server configuration and clear stored OAuth credentials in your AI client.
Removing the MCP server does not delete your API key on Sevalla. To revoke it, go to [app.sevalla.com/api-keys](https://app.sevalla.com/api-keys).
For details on how to uninstall for a specific AI client, refer to one of the following:
* [Claude Code](https://docs.sevalla.com/quick-starts/coding-agents/claude-code)
* [Codex](https://docs.sevalla.com/quick-starts/coding-agents/codex)
* [Cursor](https://docs.sevalla.com/quick-starts/coding-agents/cursor)
* [Windsurf](https://docs.sevalla.com/quick-starts/coding-agents/windsurf)
* [OpenCode](https://docs.sevalla.com/quick-starts/coding-agents/opencode)
# Windsurf
Source: https://docs.sevalla.com/quick-starts/coding-agents/windsurf
Connect Windsurf to the Sevalla MCP server using the MCP UI or manual JSON configuration.
Use this guide to connect Windsurf to the Sevalla MCP server at `https://mcp.sevalla.com/mcp`.
After setup, Cascade can call Sevalla MCP tools like `search` and `execute`.
## Quick setup (MCP UI + OAuth)
OAuth is the recommended authentication method.
Windsurf does not currently provide a dedicated MCP CLI flow. Use the MCP UI for the fastest setup:
1. Open Cascade and click the **MCPs** icon.
2. Add a new custom MCP server.
3. Set:
* Name: `sevalla`
* URL: `https://mcp.sevalla.com/mcp`
4. Click install, then complete the browser OAuth flow when prompted.
## Manual configuration (`mcp_config.json`)
Edit `~/.codeium/windsurf/mcp_config.json`:
```json theme={null}
{
"mcpServers": {
"sevalla": {
"serverUrl": "https://mcp.sevalla.com/mcp"
}
}
}
```
If you need API key auth instead of OAuth:
```json theme={null}
{
"mcpServers": {
"sevalla": {
"serverUrl": "https://mcp.sevalla.com/mcp",
"headers": {
"Authorization": "Bearer ${env:SEVALLA_API_KEY}"
}
}
}
}
```
## Configuration scope
Windsurf MCP configuration is user-level through `~/.codeium/windsurf/mcp_config.json`.
If your team uses Windsurf admin allowlists, server entries must also match team policy.
## Uninstall
Delete the `sevalla` entry from `~/.codeium/windsurf/mcp_config.json`.
## Reference
* Sevalla MCP endpoint: `https://mcp.sevalla.com/mcp`
* Sevalla MCP repository: [github.com/sevalla-hosting/mcp](https://github.com/sevalla-hosting/mcp)
# JavaScript
Source: https://docs.sevalla.com/quick-starts/javascript
Discover more about running JavaScript applications and sites on Sevalla.
[JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript#:~:text=JavaScript%20\(JS\)%20is%20a%20lightweight,language%20with%20first%2Dclass%20functions.) is a high-level, versatile programming language primarily used for building interactive web applications. Originally designed for client-side scripting in browsers, it is now widely used on the server-side through Node.js, enabling full-stack development with a single language. JavaScript has a rich ecosystem of frameworks and libraries, such as Express, Next.js, NestJS, and SvelteKit, that simplify routing, API development, database integration, and frontend rendering. JavaScript integrates seamlessly with modern deployment environments, including cloud platforms, containers, and serverless architectures, making it a popular choice for hosting web apps.
## Framework guides
* [Astro](https://docs.sevalla.com/quick-starts/javascript/astro)
* [Bun](https://docs.sevalla.com/quick-starts/javascript/bun)
* [Deno](https://docs.sevalla.com/quick-starts/javascript/deno)
* [Express](https://docs.sevalla.com/quick-starts/javascript/express)
* [Fastify](https://docs.sevalla.com/quick-starts/javascript/fastify)
* [NestJS](https://docs.sevalla.com/quick-starts/javascript/nest)
* [Next.js](https://docs.sevalla.com/quick-starts/javascript/next)
* [Nuxt.js](https://docs.sevalla.com/quick-starts/javascript/nuxt)
* [Puppeteer](https://docs.sevalla.com/quick-starts/javascript/puppeteer)
* [Remix](https://docs.sevalla.com/quick-starts/javascript/remix)
* [SvelteKit](https://docs.sevalla.com/quick-starts/javascript/sveltekit)
* [TanStack](https://docs.sevalla.com/quick-starts/javascript/tanstack)
* [Turborepo](https://docs.sevalla.com/quick-starts/javascript/turborepo)
## Supported runtimes
Sevalla supports the following JavaScript runtimes:
* **Node.js:** The most widely used runtime for server-side JavaScript.
* **Deno:** A secure, modern runtime with built-in tooling.
* **Bun:** A fast, all-in-one JavaScript runtime, bundler, and package manager.
## Supported package managers
Sevalla fully supports the major JavaScript package managers (**npm**, **Yarn**, and **pnpm**). You can define the package manager for your project in the `packageManager` field of `package.json`, and Sevalla will automatically use it during builds.
Within your `package.json`, it’s important to provide accurate values for the `engines` and `packageManager` fields. Both Buildpacks and Nixpacks read and respect these settings to ensure consistent builds.
* `engines` defines the required versions of Node.js and npm/yarn/pnpm that your project depends on. This helps prevent runtime mismatches and ensures your application runs in a compatible environment.
* `packageManager` specifies which package manager, and which exact version, should be used. This ensures consistent dependency installation across local development, CI/CD, and production.
These fields together help maintain predictable builds and avoid issues caused by mismatched runtimes or conflicting lockfiles.
For example, to use Node.js 18+, npm 9+, and ensure all environments use the same npm version:
```javascript theme={null}
...
"engines": {
"node": ">=18.17.0 <21",
"npm": ">=9"
},
"packageManager": "npm@10.5.2"
}
```
## Best practices
### Stateless
Make your applications stateless. With stateless applications, you can use horizontal scaling, which means you can run multiple instances simultaneously because no instance depends on its own in-memory data.
Stateless applications are also safer to deploy and more reliable because every instance behaves identically, and shared data lives outside the app itself.
To ensure your application can scale reliably and support zero-downtime deployments, all stateful data must be stored outside the application container. Follow these best practices:
1. **Use external session storage:** Store user sessions in a shared system, allowing any application instance to serve any request. You can host a [Redis database](https://docs.sevalla.com/databases/get-started/add-a-database) in Sevalla and use it as your external session store.
2. **Use external caching for arbitrary data:** Do not cache data in memory within the application.
Instead, use a [Redis instance](https://docs.sevalla.com/databases/get-started/add-a-database) hosted in Sevalla to store cached values that need to be shared across instances.
3. **Store uploads outside the application (stateless file handling):** User uploads should never be stored on the app’s local file system. Use Sevalla's [object storage](https://docs.sevalla.com/object-storage/overview) for hosting files, images, and videos.
4. **Use database connection pooling over the internal private network:** If your database is hosted in Sevalla, [connect via the internal private network](https://docs.sevalla.com/databases/networking) to reduce latency and improve security. Use connection pooling to efficiently manage database connections across multiple instances.
5. **Use environment variables for configuration:** All environment-specific configuration (API keys, secrets, feature flags, etc.) should be stored in [environment variables](https://docs.sevalla.com/applications/environment-variables), not in code or files.
### Object storage
Sevalla’s object storage, powered by Cloudflare R2, provides secure, scalable, and persistent storage for files in your JavaScript or TypeScript app. Its S3-compatible API makes it easy to manage uploads, downloads, and assets, ideal for user uploads, backend outputs, or serving media, while keeping your data private and reliably accessible. For step-by-step instructions on integrating object storage into your JavaScript app, see our [Object storage integration guide](https://docs.sevalla.com/quick-starts/javascript/object-storage-integration).
### Horizontal scaling
Use the following best practices for scaling your JavaScript application on Sevalla:
* **Keep your app stateless** – Avoid in-memory sessions or local file storage to ensure reliability and scalability.
* **Leverage external services** – Use managed [databases](https://docs.sevalla.com/databases/overview), [Redis](https://docs.sevalla.com/quick-starts/javascript/redis-integration), or S3 for data persistence and caching.
* **Enable** [**auto-scaling**](https://docs.sevalla.com/applications/scalability) – Allow your application to handle fluctuating traffic efficiently.
* **Maintain high availability** – Start with at least two instances to ensure redundancy.
* **Monitor resource usage** – Track CPU and memory to optimize instance count and performance.
### Redis
We recommend integrating Redis with your JavaScript application on Sevalla to boost performance and scalability. By storing frequently accessed data in memory, Redis reduces database load and accelerates response times. It also enables real-time features, such as live notifications or chat, and supports robust background job processing, making it easier to handle high-traffic scenarios and improve overall application responsiveness. For step-by-step instructions on integrating Redis into your JavaScript app, see our [Redis integration guide](https://docs.sevalla.com/quick-starts/javascript/redis-integration).
### Health checks
Configure zero-downtime deployments with [health checks](https://docs.sevalla.com/applications/deployments#zero-downtime-with-health-checks). Health checks ensure new instances are ready before receiving traffic, enabling rolling deployments without interruptions.
### Graceful shutdown
Implement graceful shutdown handling to ensure your application completes in-flight requests and properly cleans up resources when containers are stopped.
### Deployment pipelines
Use [deployment pipelines](https://docs.sevalla.com/applications/get-started/pipelines) to test changes in a staging environment before promoting them to production, thereby avoiding the introduction of regressions.
# Astro
Source: https://docs.sevalla.com/quick-starts/javascript/astro
This guide explains how to deploy a basic Astro site to Sevalla.
[Astro](https://astro.build/) is a modern, content-focused web framework designed to build fast, lightweight, and highly optimized websites. Its core philosophy is “Ship Less JavaScript”, meaning Astro renders as much of your site as possible to static HTML and only loads JavaScript in the browser when necessary.
Astro can be deployed using either Application Hosting (SSR) or Static Site Hosting (SSG). The [deployment mode](https://docs.astro.build/en/reference/configuration-reference/#output) is determined by how you configure your `astro.config.mjs` file. Astro’s `defineConfig.output` setting can only be set to `static` or `server`you cannot mix both modes within a single project.
By default, Astro generates a fully static site (SSG). To use SSR, you must explicitly opt in by setting`prerender: false`. If any part of your application uses `prerender: false`, includes server-only code, or depends on dynamic rendering, you should use Application Hosting instead of Static Site Hosting.
## Application Hosting
Choose Application Hosting (Server-Side Rendering) when your application requires server-side logic or dynamic behavior that static files cannot provide.
### Configuration
We recommend the following best practices for configuring Astro as an SSR on Sevalla:
* Use Astro’s partial hydration (`client:*` directives) only for components that need interactivity.
* Leverage static generation (SSG) whenever possible for better performance.
* Use `output: "server"` only for pages that truly require SSR.
* Enable compression middleware in your Node adapter for smaller responses.
* Optimize images using Astro’s built-in `` component.
* Sanitize and validate environment variables, and never expose secrets using the `PUBLIC_` prefix.
* Use HTTPS in production for secure communication.
* Implement rate limiting for API routes to prevent abuse.
* Add an `/api/health` endpoint for health checks.
* Configure structured logging for easier debugging and observability.
* Monitor build sizes and server response times to maintain performance.
The following is an example `astro.config.mjs` file for deploying an Astro SSR app on Sevalla:
```typescript theme={null}
// astro.config.mjs
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
export default defineConfig({
output: "server", // Enable SSR
adapter: node({
mode: "standalone", // Required for Sevalla deployments
}),
server: {
host: true, // Listen on all network interfaces
port: process.env.PORT || 4321,
},
});
```
### Containerization
#### Dockerfile
The build for [Dockerfiles](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. The following is an example Dockerfile for Astro:
```javascript expandable theme={null}
# Dockerfile for Astro on Sevalla
FROM node:lts-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:lts-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:lts-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=3000
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 astrouser
COPY --from=builder --chown=astrouser:nodejs /app/dist ./dist
COPY --from=builder --chown=astrouser:nodejs /app/package*.json ./
RUN npm ci --only=production
USER astrouser
EXPOSE 3000
CMD ["node", "./dist/server/entry.mjs"]
```
#### Nixpacks
You can customize the [Nixpacks](https://docs.sevalla.com/applications/build-options/nixpacks) build process by defining a `nixpacks.toml` file and using [**Nixpacks-specific environment variables**](https://nixpacks.com/docs/configuration/environment). This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.
The following is an example `nixpacks.toml` configuration:
```javascript theme={null}
[phases.setup]
nixPkgs = ["nodejs", "yarn"]
[phases.install]
cmds = ["yarn install --frozen-lockfile"]
[phases.build]
cmds = ["yarn build"]
[start]
cmd = "yarn start"
```
Nixpacks will automatically detect your project’s lock file and select the appropriate package manager during deployment.
Additionally, you can specify the [**Node.js version**](https://nixpacks.com/docs/providers/node) used during the build by setting the `NIXPACKS_NODE_VERSION`[**environment variable**](https://nixpacks.com/docs/providers/node#:~:text=Setting%20the%20NIXPACKS_NODE_VERSION%20environment%20variable).
#### Buildpacks
If you're using [Buildpacks](https://docs.sevalla.com/applications/build-options/buildpacks), you cannot modify the underlying build phases directly or control dependencies. You must rely on the runtime environment that Buildpacks detects.
You can influence the build process by adjusting the `build` script in your `package.json`. Buildpacks will run whatever command you specify under the build script. For example, the standard command used to compile an Astro application is:
```javascript theme={null}
"build": "astro build"
```
You can also add additional logic before the build runs, for example:
```javascript theme={null}
"build": "echo \"Hi mom!\" && astro build"
```
### CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your Astro application, we recommend the following best practices:
* [Enable the CDN](https://docs.sevalla.com/applications/cdn) for all production applications.
* Use Astro’s `` component for automatic image optimization and responsive delivery.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [Purge the CDN cache](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after deploying critical updates to avoid serving stale content.
* Leverage Astro’s fingerprinted assets in the `_astro/` directory for safe long-term caching.
* Organize static files in the `public/` directory for optimal delivery through the CDN.
* Use `getStaticPaths` for dynamic routes to pre-render content at build time.
* Combine static generation with incremental builds for frequently updated content.
### Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your Astro application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers on server-rendered pages to control caching behavior.
* Combine edge caching with the CDN to cover both dynamic and static assets.
* Monitor cache efficiency using the `cf-cache-status` header returned by Cloudflare.
Fully static pages are cached indefinitely by default, providing maximum performance.
Edge caching works best when you combine static and dynamic content with proper cache headers. Below are strategies to optimize your Astro application on Sevalla for edge caching.
#### `Cache-Control`
With Sevalla’s Cloudflare integration, Cache-Control headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your Astro application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets (e.g., files in `dist/_astro/`), allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user's browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
For example:
```javascript theme={null}
// src/pages/api/public-data.ts
import type { APIRoute } from "astro";
export const GET: APIRoute = async () => {
const data = await fetchPublicData();
return new Response(JSON.stringify(data), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, s-maxage=3600",
},
});
};
```
#### API routes with edge caching
Edge-cache API responses by returning appropriate headers in your API routes. This speeds up API responses for repeated requests and reduces load on your origin server.
```typescript theme={null}
// src/pages/api/products.ts
import type { APIRoute } from "astro";
export const GET: APIRoute = async () => {
const products = await fetchProducts();
return new Response(JSON.stringify(products), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, s-maxage=3600",
},
});
};
```
#### Time-based revalidation
Use short-lived caching for content that updates frequently. This ensures frequently updated pages remain fresh and balances edge caching with dynamic content delivery.
```typescript theme={null}
---
// src/pages/news.astro
export const prerender = false;
const cacheTime = 300; // 5 minutes
const news = await fetchNews();
Astro.response.headers.set(
'Cache-Control',
`public, s-maxage=${cacheTime}`
);
---
{news.map(item => (
{item.title}
))}
```
### Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
* Close connections cleanly (e.g., database pools, Redis) to prevent resource leaks.
* Test deployments in staging with monitoring scripts to validate health checks.
**Basic health check**
```typescript theme={null}
// src/pages/api/health.ts
import type { APIRoute } from "astro";
export const GET: APIRoute = async () => {
return new Response(
JSON.stringify({
status: "ok",
timestamp: new Date().toISOString(),
}),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
};
```
### Multi-tenancy
Sevalla fully supports multi-tenancy. You can build multi-tenant Astro applications using [**wildcard domains**](https://docs.sevalla.com/applications/domains), allowing you to serve multiple tenants from separate subdomains efficiently and securely. Use the following best practices for multi-tenancy on Sevalla with your Astro application:
* Use wildcard domains to serve subdomain-based tenants (e.g., `tenant1.app.com`).
* Add custom domains individually for tenants who have their own domains.
* Cache tenant data to reduce database queries and improve performance.
* Validate tenant existence before rendering pages to prevent errors or unauthorized access.
* Isolate tenant data in the database using separate schemas or a `tenant_id` column.
* Leverage free SSL certificates, which are automatically provided for both wildcard and custom domains.
#### Astro multi-tenant implementation
Below is a reference architecture for extracting tenant information from the hostname and injecting it into Astro’s request lifecycle.
**Extract tenant from subdomain (middleware)**
```typescript theme={null}
// src/middleware.ts
import { defineMiddleware } from "astro:middleware";
export const onRequest = defineMiddleware(async (context, next) => {
const hostname = context.request.headers.get("host") || "";
const subdomain = hostname.split(".")[0];
// Skip for main domain
if (subdomain === "www" || subdomain === "yourdomain") {
return next();
}
// Add tenant to locals for access in pages
context.locals.tenantId = subdomain;
return next();
});
```
**Use tenant information in pages**
```typescript theme={null}
---
// src/pages/index.astro
import { getTenantData } from '../lib/tenant';
const tenantId = Astro.locals.tenantId;
const tenant = await getTenantData(tenantId);
---
Welcome to {tenant?.name || 'Our Platform'}
Welcome to {tenant?.name}
Tenant ID: {tenantId}
```
**Tenant metadata lookup**
```typescript theme={null}
// src/lib/tenant.ts
import { pool } from "./db";
export async function getTenantData(tenantId: string | undefined) {
if (!tenantId) return null;
const result = await pool.query(
"SELECT * FROM tenants WHERE subdomain = $1",
[tenantId]
);
return result.rows[0] || null;
}
```
**Tenant-aware API routes**
```typescript theme={null}
// src/pages/api/data.ts
import type { APIRoute } from "astro";
import { getTenantData } from "../../lib/tenant";
export const GET: APIRoute = async ({ locals }) => {
const tenant = await getTenantData(locals.tenantId);
if (!tenant) {
return new Response(JSON.stringify({ error: "Tenant not found" }), {
status: 404,
headers: { "Content-Type": "application/json" },
});
}
return new Response(JSON.stringify(tenant), {
headers: { "Content-Type": "application/json" },
});
};
```
#### Custom domains per tenant
Tenants may want to use their own domains instead of subdomains. Sevalla supports this through domain mapping.
```typescript theme={null}
// src/middleware.ts
import { defineMiddleware } from "astro:middleware";
import { getTenantByDomain } from "./lib/tenant";
export const onRequest = defineMiddleware(async (context, next) => {
const hostname = context.request.headers.get("host") || "";
const tenant = await getTenantByDomain(hostname);
context.locals.tenantId = tenant?.id || hostname.split(".")[0];
return next();
});
```
### Troubleshooting common SSR issues
#### Cannot use import.meta.env on the client
* Use the `PUBLIC_` prefix for any environment variables that must be exposed to client-side code.
* Keep all server-only variables **unprefixed** and ensure they are accessed only in server-side modules.
#### Route handler not found
* Confirm the file is located in the correct directory: `src/pages/`.
* Check that the file uses a supported extension: `.astro`, `.js`, or `.ts`.
* Verify that your `output` mode in `astro.config.mjs` matches your intended deployment (e.g., `server` for SSR).
## Static Site Hosting
Static Site Generation (SSG) pre-renders all pages as static HTML files at build time, delivering fast and reliable performance. Use SSG when your site includes:
* Content that changes infrequently, such as blog posts, documentation, or product catalogs.
* Pages that can be pre-rendered for all users without personalization.
* Requirements for maximum performance and minimal hosting costs.
* A global audience, as static pages benefit from fast CDN distribution.
### Configuration
To deploy a static Astro site on Sevalla, set `output: "static"` in your `astro.config.mjs` file and ensure that no pages or components use `prerender: false`, which would force SSR.
/
```javascript theme={null}
export default defineConfig({
output: "static", // SSG by default
adapter: node({
mode: "standalone",
}),
});
```
### **Creating SSG pages**
All `.astro` pages are automatically pre-rendered at build time in static mode:
```
---
// src/pages/my-static-page.astro
// This page is automatically static (SSG)
const data = await fetchData(); // Runs at build time
---
Static Page
Built at: {new Date().toISOString()}
```
### **Dynamic routes with SSG**
Generate multiple pages from data using `getStaticPaths()`:
```
---
// src/pages/blog/[slug].astro
export async function getStaticPaths() {
const posts = await fetchBlogPosts();
return posts.map(post => ({
params: { slug: post.slug },
props: { post }
}));
}
const { post } = Astro.props;
---
{post.title}
```
This generates a static page for each blog post at build time.
### [****](https://docs.sevalla.com/quick-starts/javascript/next#configuration-2)
# Bun
Source: https://docs.sevalla.com/quick-starts/javascript/bun
This guide explains how to deploy a basic Bun site to Sevalla.
[Bun](https://bun.com/) is a fast, modern JavaScript runtime built with Zig and powered by the JavaScriptCore engine. It focuses on high performance, offering quick startup times, fast package installs, and a built-in HTTP server. Bun includes a package manager, bundler, test runner, and TypeScript/JSX transpiler out of the box, providing an all-in-one environment for building JavaScript applications.
Key features include:
* Native Bun HTTP server using `Bun.serve()` .
* No build step required - TypeScript runs directly.
* Built-in TypeScript support - No transpilation needed.
* Fast startup - Instant server boot.
* Minimal dependencies - Only `@types/bun` for development.
* Health check endpoint included.
Bun can only be used on Application Hosting; it cannot be deployed as a static site.
## Configuration
With Bun, no build step is required. Bun runs TypeScript directly, so you don't need a separate build command. Sevalla will automatically:
1. Run `bun install` to install dependencies.
2. Execute `bun run start` to start your server.
The following is an example `package.json` file for deploying Bun on Sevalla:
```json theme={null}
{
"scripts": {
"start": "bun run src/index.ts"
}
}
```
## Containerization
### Dockerfile
The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. The Dockerfile below follows best practices for building and running a Bun application in Sevalla. It:
* Uses official `oven/bun` image for optimal performance.
* Installs dependencies with `--frozen-lockfile` for deterministic builds.
* Exposes port 3000 by default.
* Runs the application using `bun run start` .
* Excludes unnecessary files via `.dockerignore` (node\_modules, .git, .env, etc.).
```javascript theme={null}
FROM oven/bun
WORKDIR /app
COPY package.json ./
RUN bun install --frozen-lockfile
COPY . .
EXPOSE 3000
ENV PORT=3000
CMD ["bun", "run", "start"]
```
### Nixpacks
[**Nixpacks**](https://docs.sevalla.com/applications/build-options/nixpacks) detects Bun projects automatically by locating a `package.json` and `bun.lock` file in your application. It then installs the Bun runtime, runs `bun install` to fetch dependencies, and uses the `start` script from your `package.json` file to configure how your application is launched.
You must use **Nixpacks v1.39** or newer for proper Bun support. You can set the Nixpacks version within **Applications** > ***Application name*** > **Settings** > **Update build strategy**.
When using Nixpacks in Sevalla for your Bun application:
* Ensure your `package.json` has a valid `start` script.
* Nixpacks respects your `bun.lock` file for deterministic builds.
* All standard Sevalla features (CDN, scaling, processes) work with Nixpacks.
* Nixpacks uses Node 18 by default, but Bun requires Node 22. To ensure compatibility, set the `NIXPACKS_NODE_VERSION` environment variable to `22`.
## CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your Bun application, we recommend the following best practices:
* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications to ensure global, low-latency delivery.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after critical deployments to ensure users receive updated content.
* Use versioned URLs for static assets (e.g., `/static/app.v123.js`).
### Optimizing Bun server for CDN
#### Static files with cache headers
```javascript theme={null}
// src/index.ts
const server = Bun.serve({
port: process.env.PORT || 3000,
fetch(req) {
const url = new URL(req.url);
// Serve static assets with caching
if (url.pathname.startsWith("/static/")) {
const file = Bun.file(`./public${url.pathname}`);
return new Response(file, {
headers: {
"Cache-Control": "public, max-age=31536000, immutable",
"Content-Type": file.type,
},
});
}
// API endpoint with shorter cache
if (url.pathname === "/api/data") {
const data = { message: "Hello from Bun!" };
return new Response(JSON.stringify(data), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, max-age=3600, s-maxage=3600",
},
});
}
return new Response("Not Found", { status: 404 });
},
});
```
## Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your Bun application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.
### Optimizing Bun for edge caching
```javascript theme={null}
// src/index.ts
const server = Bun.serve({
port: process.env.PORT || 3000,
fetch(req) {
const url = new URL(req.url);
// API with edge caching
if (url.pathname === "/api/products") {
const products = getProducts(); // Your data fetching logic
return new Response(JSON.stringify(products), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, max-age=60, s-maxage=3600",
},
});
}
// User-specific data (don't cache)
if (url.pathname === "/api/user/profile") {
return new Response(JSON.stringify({ user: "data" }), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "private, no-cache",
},
});
}
return new Response("Not Found", { status: 404 });
},
});
```
### `Cache-Control`
With Sevalla’s Cloudflare integration, `Cache-Control` headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your Bun application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
## Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
### Basic healthcheck
```javascript theme={null}
// src/index.ts
const server = Bun.serve({
port: process.env.PORT || 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/api/health") {
return new Response(
JSON.stringify({
status: "ok",
timestamp: new Date().toISOString(),
runtime: "Bun",
version: Bun.version,
}),
{
headers: { "Content-Type": "application/json" },
}
);
}
return new Response("Not Found", { status: 404 });
},
});
```
## Graceful shutdown
Bun supports graceful shutdown by default. For custom cleanup logic, use `SIGTERM` and `SIGINT` , for example:
```javascript theme={null}
// src/index.ts
import { pool } from "./lib/db";
const server = Bun.serve({
port: process.env.PORT || 3000,
fetch(req) {
// ... your routes
},
});
// Graceful shutdown
process.on("SIGTERM", async () => {
console.log("Received SIGTERM, closing connections...");
// Close database pool
await pool.end();
// Stop server
server.stop();
console.log("Server closed gracefully");
process.exit(0);
});
process.on("SIGINT", async () => {
console.log("Received SIGINT, closing connections...");
await pool.end();
server.stop();
process.exit(0);
});
```
## S3
Bun includes a [built-in s3 package](https://bun.com/docs/runtime/s3) that integrates seamlessly with Sevalla's [object storage](https://docs.sevalla.com/object-storage/overview).
You can also integrate your Bun application with AWS S3 for object storage, file uploads, and static assets.
### Set up AWS S3
1. **Install AWS SDK dependency:**
```javascript theme={null}
bun add @aws-sdk/client-s3
```
2. **Set S3 environment variables:**
```javascript theme={null}
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your_access_key_here
S3_SECRET_ACCESS_KEY=your_secret_key_here
S3_ENDPOINT=https://s3.sevalla.com
S3_BUCKET_NAME=your_bucket_name
```
For production, use your Sevalla S3 service credentials or external S3-compatible provider (AWS S3, Cloudflare R2, MinIO, etc.)
### AWS S3 Usage
The S3 client is initialized in `src/s3.ts`:
```javascript theme={null}
import { S3Client } from "@aws-sdk/client-s3";
const s3Client = new S3Client({
region: process.env.S3_REGION || "us-east-1",
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID || "",
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY || "",
},
endpoint: process.env.S3_ENDPOINT,
});
export default s3Client;
```
# Deno
Source: https://docs.sevalla.com/quick-starts/javascript/deno
This guide explains how to deploy a basic Deno site to Sevalla.
[Deno](https://deno.com/) is a modern, secure runtime for JavaScript and TypeScript. It is built with Rust and emphasizes security by requiring explicit permissions for file, network, or environment access. Deno supports TypeScript natively, includes a standard library, and utilizes URL-based module imports instead of a centralized package manager, providing a streamlined and secure alternative for server-side development and scripting.
Deno can only be used on Application Hosting; it cannot be deployed as a static site.
## Configuration
Deno runs TypeScript directly, eliminating the need for a separate build or installation step. With Sevalla:
* Dependencies are cached automatically on the first build.
* Your app can be started using `deno task start` or any custom start command you configure.
The following is an example `deno.json` file:
```javascript theme={null}
{
"tasks": {
"start": "deno run --allow-net --allow-env --allow-read src/index.ts"
}
}
```
Ensure your start command includes all necessary **permission flags** for production:
* `--allow-net` - Enables network access (required for HTTP servers).
* `--allow-env` - Access to environment variables.
* `--allow-read` - File system read access (if needed).
* `--allow-write` - File system write access (if needed).
## Containerization
### Dockerfile
The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. The following is an example Dockerfile for Deno:
```javascript theme={null}
FROM denoland/deno:latest
WORKDIR /app
COPY . .
RUN deno cache src/main.ts
EXPOSE 3000
ENV PORT=3000
CMD ["deno", "run", "--allow-net", "--allow-env", "src/main.ts"]
```
### Nixpacks
Nixpacks automatically detects Deno projects by looking for:
1. `deno.json` or `deno.jsonc` in the project root.
2. Deno imports in TypeScript files.
3. `deps.ts` file (common Deno convention).
Once detected, Nixpacks will:
* Install the latest Deno runtime.
* Cache dependencies from remote imports.
* Execute your start command as defined in `deno.json` .
For example, if you have a `deno.json` with a `start` task, as follows:
```javascript theme={null}
{
"tasks": {
"start": "deno run --allow-net --allow-env src/index.ts"
}
}
```
Nixpacks will automatically install Deno and run `deno task start` to start your application.
#### Custom configuration with `nixpacks.toml`
You can customize the [**Nixpacks**](https://docs.sevalla.com/applications/build-options/nixpacks) build process by defining a `nixpacks.toml` file and using [**Nixpacks-specific environment variables**](https://nixpacks.com/docs/configuration/environment). This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.
The following is an example `nixpacks.toml` configuration:
```javascript theme={null}
# nixpacks.toml
[phases.setup]
nixPkgs = ["deno"]
[phases.install]
# Cache dependencies by running a command that imports them
cmds = ["deno cache src/index.ts"]
[phases.build]
# Optional: Run build steps if needed
cmds = ["deno task build"]
[start]
cmd = "deno task start"
```
#### Common Nixpacks configurations
**Basic Deno application**
```javascript theme={null}
# nixpacks.toml
[phases.setup]
nixPkgs = ["deno"]
[start]
cmd = "deno run --allow-net --allow-env src/index.ts"
```
**Deno with specific version**
```javascript theme={null}
# nixpacks.toml
[phases.setup]
nixPkgs = ["deno"]
[phases.install]
cmds = ["deno upgrade --version 1.40.0"]
[start]
cmd = "deno task start"
```
**Deno with additional system dependencies**
```javascript theme={null}
# nixpacks.toml
[phases.setup]
# Add additional system packages if needed (e.g., for image processing)
nixPkgs = ["deno", "imagemagick", "ffmpeg"]
[phases.install]
cmds = ["deno cache src/index.ts"]
[start]
cmd = "deno task start"
```
**Monorepo with custom build path**
```javascript theme={null}
# nixpacks.toml (in monorepo root)
[phases.setup]
nixPkgs = ["deno"]
[phases.install]
cmds = ["cd apps/api && deno cache src/index.ts"]
[start]
cmd = "cd apps/api && deno task start"
```
**Deno with environment-specific builds**
```javascript theme={null}
# nixpacks.toml
[phases.setup]
nixPkgs = ["deno"]
[phases.build]
# Generate static files or run build tasks
cmds = [
"deno task build",
"deno run --allow-read --allow-write scripts/generate-config.ts"
]
[start]
cmd = "deno task start"
```
For more information about Nixpacks with Deno, refer to the [Nixpacks Deno documentation](https://nixpacks.com/docs/providers/deno).
## CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your Deno application, we recommend the following best practices:
* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge the CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after deploying critical updates to avoid serving stale content.
* Use versioned URLs for static assets, for example `/static/app.v123.js`.
### Optimizing Deno for CDN
#### Static files with cache headers
```javascript theme={null}
// src/index.ts
import { serveFile } from "https://deno.land/std@0.208.0/http/file_server.ts";
Deno.serve({ port: Number(Deno.env.get("PORT") || "3000") }, async (req) => {
const url = new URL(req.url);
// Serve static assets with caching
if (url.pathname.startsWith("/static/")) {
try {
const filePath = `./public${url.pathname}`;
const response = await serveFile(req, filePath);
response.headers.set(
"Cache-Control",
"public, max-age=31536000, immutable"
);
return response;
} catch {
return new Response("Not Found", { status: 404 });
}
}
// API endpoint with shorter cache
if (url.pathname === "/api/data") {
const data = { message: "Hello from Deno!" };
return new Response(JSON.stringify(data), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, max-age=3600, s-maxage=3600",
},
});
}
return new Response("Not Found", { status: 404 });
});
```
## Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your Deno application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.
### Optimizing Deno for edge caching
```javascript theme={null}
// src/index.ts
Deno.serve({ port: Number(Deno.env.get("PORT") || "3000") }, (req) => {
const url = new URL(req.url);
// API with edge caching
if (url.pathname === "/api/products") {
const products = getProducts(); // Your data fetching logic
return new Response(JSON.stringify(products), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, max-age=60, s-maxage=3600",
},
});
}
// User-specific data (don't cache)
if (url.pathname === "/api/user/profile") {
return new Response(JSON.stringify({ user: "data" }), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "private, no-cache",
},
});
}
return new Response("Not Found", { status: 404 });
});
```
#### `Cache-Control`
With Sevalla’s Cloudflare integration, `Cache-Control` headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your Deno application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
## Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
### Basic health check
```javascript theme={null}
// src/index.ts
Deno.serve({ port: Number(Deno.env.get("PORT") || "3000") }, (req) => {
const url = new URL(req.url);
if (url.pathname === "/api/health") {
return new Response(
JSON.stringify({
status: "ok",
timestamp: new Date().toISOString(),
runtime: "Deno",
version: Deno.version.deno,
}),
{
headers: { "Content-Type": "application/json" },
}
);
}
return new Response("Not Found", { status: 404 });
});
```
## Graceful shutdown
Deno supports graceful shutdown signals. For custom cleanup logic, such as closing database connections, use `SIGTERM` and `SIGINT`, for example:
```javascript theme={null}
// src/index.ts
import { pool } from "./lib/db.ts";
const abortController = new AbortController();
Deno.serve(
{
port: Number(Deno.env.get("PORT") || "3000"),
signal: abortController.signal,
},
(req) => {
// ... your routes
}
);
// Graceful shutdown
Deno.addSignalListener("SIGTERM", async () => {
console.log("Received SIGTERM, closing connections...");
// Close database pool
await pool.end();
// Stop server
abortController.abort();
console.log("Server closed gracefully");
Deno.exit(0);
});
Deno.addSignalListener("SIGINT", async () => {
console.log("Received SIGINT, closing connections...");
await pool.end();
abortController.abort();
Deno.exit(0);
});
```
## S3
You can integrate your Deno application with S3 (Sevalla S3, AWS S3, or any S3-compatible storage) using the AWS SDK or JavaScript v3.
### Setup
1. **Install dependencies** (auto-cached on first run):
```javascript theme={null}
import {
S3Client,
ListBucketsCommand,
PutObjectCommand,
GetObjectCommand,
DeleteObjectCommand,
} from "npm:@aws-sdk/client-s3@^3.400.0";
```
2. **Configure environment variables**:
```javascript theme={null}
S3_REGION=us-east-1
S3_ENDPOINT=https://s3.sevalla.com # Optional: for S3-compatible services
S3_ACCESS_KEY_ID=your_access_key_here
S3_SECRET_ACCESS_KEY=your_secret_key_here
```
# Express
Source: https://docs.sevalla.com/quick-starts/javascript/express
This guide explains how to deploy a basic Express site to Sevalla.
[Express](https://expressjs.com/) is a minimalist and flexible web framework for Node.js, designed to simplify and streamline the building of APIs and web applications. It provides a lightweight routing system, middleware support, and a straightforward API that gives developers full control without unnecessary complexity. Express is widely used due to its ease of use, large ecosystem of plugins, and compatibility with virtually any Node.js architecture, making it a popular choice for both small projects and large-scale applications.
Express can only be used on Application Hosting; it cannot be deployed as a static site.
## Configuration
With Express, you can either compile TypeScript to JavaScript for production or run TypeScript directly.
### Compile to JavaScript (recommended for production)
* Sevalla will run `npm run build` followed by `npm start`
* Provides faster startup and better runtime performance
Example`package.json`:
```json theme={null}
{
"scripts": {
"start": "node dist/index.js",
"build": "tsc",
"dev": "tsx watch src/index.ts"
}
}
```
### **Run TypeScript directly**
* Sevalla will run `npm start` using `tsx` or `ts-node`
* Simpler setup with no build step.
Example`package.json`:
```json theme={null}
{
"scripts": {
"start": "tsx src/index.ts",
"dev": "tsx watch src/index.ts"
}
}
```
## Containerization
### Dockerfile
The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. We recommend the following best practices when using a Dockerfile for Express on Sevalla:
* **Use Alpine images** - Smaller image size (\~40MB vs \~900MB).
* **Multi-stage builds** - Separate build and runtime dependencies.
* **Layer caching** - Copy `package.json` before the source code.
* **Security** - Run as a non-root user in production.
* **.dockerignore** - Exclude unnecessary files.
The following is an example Dockerfile for Express:
```javascript expandable theme={null}
# Build stage
FROM node:lts-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:lts-alpine
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
ENV PORT=3000
ENV HOST=0.0.0.0
ENV NODE_ENV=production
CMD ["node", "dist/index.js"]
```
### Nixpacks
[Nixpacks](https://docs.sevalla.com/applications/build-options/nixpacks) offers less customization than Dockerfiles, but you can still adjust the build process by creating a `nixpacks.toml` file and using [**Nixpacks-specific environment variables**](https://nixpacks.com/docs/configuration/environment). This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.
You can control the Node.js version used during the build by using an `.nvmrc` file, the `engines` field in `package.json`, or the `NIXPACKS_NODE_VERSION` environment variable. If none are set, Nixpacks defaults to Node.js 18.
We recommend the following best practices when using Nixpacks for Express on Sevalla:
* **Commit lock files** - Always include `package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml` for deterministic, reproducible builds.
* **Specify your Node.js version** - Use the `engines` field in `package.json` or an `.nvmrc` file to ensure consistent versioning.
* **Use npm ci** - Faster and more reliable than `npm install` in CI/CD environments.
* **Set** `NODE_ENV=production` - Helps optimize performance and reduce bundle size.
* **Test builds locally** - Use the Nixpacks CLI to identify build issues before deploying.
* **Keep configuration minimal** - Allow Nixpacks to auto-detect your setup; only add a `nixpacks.toml` file for advanced customization.
* **Optimize TypeScript builds** - After compiling, run `npm prune --production` to remove dev dependencies.
* **Define a** `start`**script** - Ensure `package.json` includes a `start` script for consistent server startup.
The following is an example `nixpacks.toml` configuration for Express:
```javascript theme={null}
# nixpacks.toml
[phases.setup]
nixPkgs = ["nodejs_22"]
[phases.install]
cmds = ["npm ci"]
[phases.build]
cmds = ["npm run build"]
[start]
cmd = "npm start"
```
### Buildpacks
[**Buildpacks**](https://docs.sevalla.com/applications/build-options/buildpacks), automatically detects your project’s lock file and installs dependencies using the appropriate package manager. When using Buildpacks, you cannot directly modify the underlying build phases or control how dependencies are installed; Buildpacks determine this based on your project’s structure and configuration.
However, you can influence the final runtime behavior by defining the appropriate `start` script in your `package.json `file, which Buildpacks will use when launching your Express application.
## CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your Express application, we recommend the following best practices:
* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge the CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after deploying critical updates to avoid serving stale content.
* Use versioned URLs for static assets, for example `/static/app.v123.js` .
### Optimizing Express for CDN
#### Static files with cache headers
```javascript theme={null}
// src/index.ts
import express from "express";
import path from "path";
const app = express();
const PORT = process.env.PORT || 3000;
// Serve static files with caching
app.use(
"/static",
express.static(path.join(__dirname, "../public"), {
maxAge: "1y", // Cache for 1 year
immutable: true,
setHeaders: (res, filePath) => {
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
},
})
);
// API endpoint with shorter cache
app.get("/api/data", (req, res) => {
const data = { message: "Hello from Express!" };
res.setHeader("Content-Type", "application/json");
res.setHeader("Cache-Control", "public, max-age=3600, s-maxage=3600");
res.json(data);
});
// 404 handler
app.use((req, res) => {
res.status(404).send("Not Found");
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
```
## Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your Express application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.
### Optimizing Express for edge caching
```javascript theme={null}
// src/index.ts
import express from "express";
const app = express();
const PORT = process.env.PORT || 3000;
// API with edge caching
app.get("/api/products", (req, res) => {
const products = getProducts(); // Your data fetching logic
res.setHeader("Content-Type", "application/json");
res.setHeader("Cache-Control", "public, max-age=60, s-maxage=3600");
res.json(products);
});
// User-specific data (don't cache)
app.get("/api/user/profile", (req, res) => {
const userData = { user: "data" };
res.setHeader("Content-Type", "application/json");
res.setHeader("Cache-Control", "private, no-cache");
res.json(userData);
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
```
#### `Cache-Control`
With Sevalla’s Cloudflare integration,`Cache-Control`headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your Express application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
## Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
### Basic health check
```javascript theme={null}
// src/index.ts
import express from "express";
const app = express();
const PORT = process.env.PORT || 3000;
app.get("/api/health", (req, res) => {
res.json({
status: "ok",
timestamp: new Date().toISOString(),
runtime: "Node.js",
version: process.version,
});
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
```
## Graceful shutdown
[****](https://docs.sevalla.com/quick-starts/javascript/fastify#configuration)Implement graceful shutdown to cleanly close connections during deployments.
The following example demonstrates how to implement a graceful shutdown in an Express server by closing HTTP server and database connections safely upon receiving deployment or termination signals:
```javascript theme={null}
// src/index.ts
import express from "express";
import { Server } from "http";
import { pool } from "./lib/db";
const app = express();
const PORT = process.env.PORT || 3000;
// ... your routes
const server: Server = app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
// Graceful shutdown
process.on("SIGTERM", async () => {
console.log("Received SIGTERM, closing connections...");
// Stop accepting new connections
server.close(async () => {
console.log("HTTP server closed");
// Close database pool
await pool.end();
console.log("Server closed gracefully");
process.exit(0);
});
// Force close after 30 seconds
setTimeout(() => {
console.error("Forced shutdown after timeout");
process.exit(1);
}, 30000);
});
process.on("SIGINT", async () => {
console.log("Received SIGINT, closing connections...");
server.close(async () => {
await pool.end();
process.exit(0);
});
});
```
# Fastify
Source: https://docs.sevalla.com/quick-starts/javascript/fastify
This guide explains how to deploy a basic Fastify site to Sevalla.
[Fastify](https://fastify.dev/) is a lightweight, high-performance web framework for Node.js, designed to deliver exceptional speed with minimal overhead. It provides a streamlined, developer-friendly API, powerful plugin architecture, and built-in schema validation for both requests and responses. With its focus on efficiency and extensibility, Fastify is well-suited for building scalable APIs and backend services that require strong performance without sacrificing maintainability.
Fastify can only be used on Application Hosting; it cannot be deployed as a static site.
## Configuration
With Fastify, you can either compile TypeScript to JavaScript for production or run TypeScript directly.
### **Compile to JavaScript (recommended for production)**
* Sevalla will run `npm run build` followed by `npm start`
* Provides faster startup and better runtime performance
Example `package.json`:
```javascript theme={null}
{
"scripts": {
"start": "node dist/index.js",
"build": "tsc",
"dev": "tsx watch src/index.ts"
}
}
```
### **Run TypeScript directly**
* Sevalla will run `npm start` using `tsx` or `ts-node`
* Simpler setup with no build step.
Example `package.json`:
```javascript theme={null}
{
"scripts": {
"start": "tsx src/index.ts",
"dev": "tsx watch src/index.ts"
}
}
```
### Required for Sevalla deployments
Ensure your Fastify server listens on all interfaces (not just `localhost`):
```javascript theme={null}
await fastify.listen({ port: PORT, host: "0.0.0.0" });
```
## Containerization
### Dockerfile
The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. We recommend the following best practices when using a Dockerfile for Fastify on Sevalla:
1. **Use Alpine images** - Smaller image size (\~40MB vs \~900MB).
2. **Multi-stage builds** - Separate build and runtime dependencies.
3. **Layer caching** - Copy `package.json` before the source code.
4. **Security** - Run as a non-root user in production.
5. **.dockerignore** - Exclude unnecessary files.
The following is an example Dockerfile for Fastify:
```javascript expandable theme={null}
# Build stage
FROM node:lts-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:lts-alpine
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
ENV PORT=3000
ENV HOST=0.0.0.0
ENV NODE_ENV=production
CMD ["node", "dist/index.js"]
```
### Nixpacks
Nixpacks automatically detects the lock file and uses the corresponding package manager during deployment. You can also modify the node version through the `NIXPACKS_NODE_VERSION` environment variable.
We recommend the following best practices when using Nixpacks for Fastify on Sevalla:
* **Commit lock files** - Always include `package-lock.json`, `yarn.lock`, or `pnpm-lock.yaml` for deterministic, reproducible builds.
* **Specify your Node.js version** - Use the `engines` field in `package.json` or an `.nvmrc` file to ensure consistent versioning.
* **Prefer** `npm ci` - More reliable and faster than `npm install` in CI/CD environments.
* **Set** `NODE_ENV=production` - Helps optimize performance and reduce bundle size.
* **Test builds locally** - Use the Nixpacks CLI to identify build issues before deploying.
* **Keep configuration minimal** - Allow Nixpacks to auto-detect your setup; only add a `nixpacks.toml` file for advanced customization.
* **Optimize TypeScript builds** - After compiling, run `npm prune --production` to remove dev dependencies.
* **Define a** `start`**script** - Ensure `package.json` includes a `start` script for consistent server startup.
Example `nixpacks.toml` file:
```javascript theme={null}
# nixpacks.toml
[phases.setup]
nixPkgs = ["nodejs_20"]
[start]
cmd = "node dist/index.js"
```
### Buildpacks
[**Buildpacks**](https://docs.sevalla.com/applications/build-options/buildpacks), automatically detects your project’s lock file and installs dependencies using the appropriate package manager. When using Buildpacks, you cannot directly modify the underlying build phases or control how dependencies are installed; Buildpacks determine this based on your project’s structure and configuration.
However, you can influence the final runtime behavior by defining the appropriate `start` script in your `package.json `file, which Buildpacks will use when launching your Fastify application.
## CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your Fastify application, we recommend the following best practices:
* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge the CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after deploying critical updates to avoid serving stale content.
* Use versioned URLs for static assets, for example `/static/app.v123.js` .
### Optimizing Fastify for CDN
#### Install the static files plugin
```javascript theme={null}
npm install @fastify/static
```
#### Static files with cache headers
```javascript theme={null}
// src/index.ts
import Fastify from "fastify";
import fastifyStatic from "@fastify/static";
import path from "path";
const fastify = Fastify({
logger: true,
});
const PORT = Number(process.env.PORT) || 3000;
// Serve static files with caching
fastify.register(fastifyStatic, {
root: path.join(__dirname, "../public"),
prefix: "/static/",
decorateReply: false,
setHeaders: (res, filePath) => {
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
},
});
// API endpoint with shorter cache
fastify.get("/api/data", async (request, reply) => {
const data = { message: "Hello from Fastify!" };
return reply
.header("Cache-Control", "public, max-age=3600, s-maxage=3600")
.send(data);
});
// 404 handler
fastify.setNotFoundHandler((request, reply) => {
return reply.status(404).send("Not Found");
});
// Start server
const start = async () => {
try {
await fastify.listen({ port: PORT, host: "0.0.0.0" });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();
```
## Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your Fastify application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.
### Optimizing Fastify for edge caching
```javascript theme={null}
// src/index.ts
import Fastify from "fastify";
const fastify = Fastify({
logger: true,
});
const PORT = Number(process.env.PORT) || 3000;
// API with edge caching
fastify.get("/api/products", async (request, reply) => {
const products = await getProducts(); // Your data fetching logic
return reply
.header("Cache-Control", "public, max-age=60, s-maxage=3600")
.send(products);
});
// User-specific data (don't cache)
fastify.get("/api/user/profile", async (request, reply) => {
const userData = { user: "data" };
return reply.header("Cache-Control", "private, no-cache").send(userData);
});
// Start server
const start = async () => {
try {
await fastify.listen({ port: PORT, host: "0.0.0.0" });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();
```
#### `Cache-Control`
With Sevalla’s Cloudflare integration,`Cache-Control`headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your Fastify application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
## Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
### **Basic health check**
```javascript theme={null}
// src/index.ts
import Fastify from "fastify";
const fastify = Fastify({ logger: true });
const PORT = Number(process.env.PORT) || 3000;
fastify.get("/api/health", async (request, reply) => {
return reply.send({
status: "ok",
timestamp: new Date().toISOString(),
runtime: "Node.js",
version: process.version,
});
});
const start = async () => {
try {
await fastify.listen({ port: PORT, host: "0.0.0.0" });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();
```
## Graceful shutdown
Fastify's built-in `close()` method handles graceful shutdown automatically by:
* Stopping the server from accepting new connections.
* Waiting for existing requests to complete.
* Closing all connections.
* Cleaning up registered plugins and hooks.
Implement graceful shutdown to cleanly close connections during deployments. For example:
```javascript theme={null}
// src/index.ts
import Fastify from "fastify";
import { pool } from "./lib/db";
const fastify = Fastify({ logger: true });
const PORT = Number(process.env.PORT) || 3000;
// ... your routes
// Graceful shutdown function
const closeGracefully = async (signal: string) => {
fastify.log.info(`Received ${signal}, closing gracefully...`);
try {
// Fastify.close() stops accepting new connections and closes server
await fastify.close();
fastify.log.info("Fastify server closed");
// Close database pool
await pool.end();
fastify.log.info("Database pool closed");
fastify.log.info("Server closed gracefully");
process.exit(0);
} catch (err) {
fastify.log.error("Error during graceful shutdown:", err);
process.exit(1);
}
};
// Listen for termination signals
process.on("SIGTERM", () => closeGracefully("SIGTERM"));
process.on("SIGINT", () => closeGracefully("SIGINT"));
// Start server
const start = async () => {
try {
await fastify.listen({ port: PORT, host: "0.0.0.0" });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();
```
# NestJS
Source: https://docs.sevalla.com/quick-starts/javascript/nest
This guide explains how to deploy a basic NestJS site to Sevalla.
[NestJS](https://nestjs.com/) is a progressive Node.js framework designed for building scalable and maintainable server-side applications. It uses TypeScript by default and follows a structured, modular architecture inspired by Angular, making it especially well-suited for large or complex projects. With built-in support for dependency injection, decorators, and powerful abstractions for HTTP, WebSockets, and microservices, NestJS provides a robust foundation for creating clean, organized, and enterprise-grade APIs.
NestJS can only be used on Application Hosting; it cannot be deployed as a static site.
## Configuration
NestJS applications require **at least an S1 pod** on Sevalla to start reliably, as the framework’s initialization and compilation process demands more memory than smaller pod sizes provide.
NestJS applications are built using the NestJS CLI, which compiles TypeScript to JavaScript. Sevalla runs `npm run build` then `npm start` and the build output goes to `dist/` directory.
The `package.json` file should include the following:
```json theme={null}
{
"scripts": {
"build": "nest build",
"start": "node dist/main",
"start:dev": "nest start --watch",
"start:prod": "node dist/main"
}
}
```
### Environment variables
Set your [environment variables](https://docs.sevalla.com/applications/environment-variables) directly in Sevalla. For managing them inside your NestJS application, we recommend the following best practices:
* Use the `@nestjs/config` package for structured environment configuration
* Install with: `npm install @nestjs/config`
* Load `.env` files automatically using `ConfigModule`
* Access variables through `ConfigService` via dependency injection
* Validate all environment variables at startup to prevent misconfiguration
* **Never** commit `.env` files to version control
Example `ConfigModule` setup:
```javascript theme={null}
// src/app.module.ts
import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: ".env",
}),
],
})
export class AppModule {}
```
## Containerization
### Dockerfile
The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. We recommend the following best practices when using a Dockerfile for NestJS on Sevalla:
* **Use Alpine images** - Smaller image size (\~40MB vs \~900MB).
* **Multi-stage builds** - Separate build and runtime dependencies.
* **Layer caching** - Copy `package.json` before the source code.
* **Security** - Run as a non-root user in production.
* **.dockerignore** - Exclude unnecessary files.
```javascript theme={null}
# Build stage
FROM node:lts-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:lts-alpine
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
ENV PORT=3000
ENV HOST=0.0.0.0
ENV NODE_ENV=production
CMD ["node", "dist/index.js"]
```
### Nixpacks
You can customize the [**Nixpacks**](https://docs.sevalla.com/applications/build-options/nixpacks) build process by defining a `nixpacks.toml` file and using [**Nixpacks-specific environment variables**](https://nixpacks.com/docs/configuration/environment). This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.
You can control the Node.js version used during the build by using an `.nvmrc` file, the `engines` field in `package.json`, or the `NIXPACKS_NODE_VERSION` environment variable. If none are set, Nixpacks defaults to Node.js 18.
The following is an example `nixpacks.toml` configuration for NestJS:
```javascript theme={null}
# nixpacks.toml
[phases.setup]
nixPkgs = ["nodejs_22"]
[phases.install]
cmds = ["npm ci"]
[phases.build]
cmds = ["npm run build"]
[start]
cmd = "npm start"
```
The following is an example `nixpacks.toml` for NestJS with additional system dependencies:
```javascript theme={null}
# nixpacks.toml
[phases.setup]
# Add additional system packages if needed (e.g., for image processing)
nixPkgs = ["nodejs_22", "imagemagick", "ffmpeg"]
[phases.install]
cmds = ["npm ci"]
[start]
cmd = "npm start"
```
### Buildpacks
Buildpacks automatically detect your project’s lock file and install dependencies using the appropriate package manager. With Buildpacks, you cannot modify the underlying build phases or control how dependencies are installed; this is determined entirely by your project’s structure and configuration.
However, you can influence the final runtime behavior by defining the correct `start` script in your `package.json`, which Buildpacks will use when launching your NestJS application.
## CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your NestJS application, we recommend the following best practices:
* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge the CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after deploying critical updates to avoid serving stale content.
* Use versioned URLs for static assets, for example `/static/app.v123.js` .
### Optimizing NestJS for CDN
#### Static files with cache headers
```javascript theme={null}
// src/main.ts
import { NestFactory } from "@nestjs/core";
import { NestExpressApplication } from "@nestjs/platform-express";
import { join } from "path";
import { AppModule } from "./app.module";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Serve static files with caching
app.useStaticAssets(join(__dirname, "..", "public"), {
prefix: "/static/",
maxAge: "1y",
immutable: true,
setHeaders: (res, path) => {
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
},
});
await app.listen(process.env.PORT || 3000);
}
bootstrap();
```
## Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your NestJS application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.
### Optimizing NestJS for edge caching
```javascript theme={null}
// src/products/products.controller.ts
import { Controller, Get, Header } from "@nestjs/common";
import { ProductsService } from "./products.service";
@Controller("api/products")
export class ProductsController {
constructor(private readonly productsService: ProductsService) {}
// API with edge caching
@Get()
@Header("Cache-Control", "public, max-age=60, s-maxage=3600")
async findAll() {
return this.productsService.findAll();
}
}
// src/user/user.controller.ts
import { Controller, Get, Header } from "@nestjs/common";
import { UserService } from "./user.service";
@Controller("api/user")
export class UserController {
constructor(private readonly userService: UserService) {}
// User-specific data (don't cache)
@Get("profile")
@Header("Cache-Control", "private, no-cache")
async getProfile() {
return this.userService.getProfile();
}
}
```
#### `Cache-Control`
With Sevalla’s Cloudflare integration,`Cache-Control`headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your NestJS application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
## Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) using `@nestjs/terminus` as part of the checks.
### Basic health check
```javascript theme={null}
// src/health/health.controller.ts
import { Controller, Get } from "@nestjs/common";
@Controller("health")
export class HealthController {
@Get()
check() {
return {
status: "ok",
timestamp: new Date().toISOString(),
runtime: "Node.js",
version: process.version,
};
}
}
```
## Graceful shutdown
NestJS has built-in support for graceful shutdown with `enableShutdownHooks()` :
```javascript theme={null}
// src/main.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Enable graceful shutdown hooks
app.enableShutdownHooks();
await app.listen(process.env.PORT || 3000);
}
bootstrap();
```
Implement `OnModuleDestroy` for custom cleanup logic for custom cleanup logic:
```javascript theme={null}
// src/app.service.ts
import { Injectable, OnModuleDestroy } from "@nestjs/common";
import { DataSource } from "typeorm";
@Injectable()
export class AppService implements OnModuleDestroy {
constructor(private dataSource: DataSource) {}
async onModuleDestroy() {
console.log("Gracefully shutting down...");
await this.dataSource.destroy();
console.log("Database connections closed");
}
}
```
# Next.js
Source: https://docs.sevalla.com/quick-starts/javascript/next
This guide explains how to deploy a basic Next.js site to Sevalla.
[Next.js](https://nextjs.org/) is a React-based full-stack web framework created by Vercel. It extends React with powerful features for server-side rendering, routing, data fetching, API endpoints, and performance optimization, all in a single unified framework.
It’s designed to help you build production-ready web applications with high performance, great developer experience, and strong scalability.
Next.js can be deployed using either Application Hosting (SSR) or Static Site Hosting (SSG). The primary difference lies in how you configure `next.config.mjs`, which determines whether pages are rendered at runtime or generated ahead of time.
## Application Hosting
Choose Application Hosting (Server-Side Rendering) when your application requires server-side logic or dynamic behavior that static files cannot provide. SSR is ideal when your site includes:
* Personalized user experiences, such as dashboards and profiles.
* Real-time or frequently changing data that must be fetched on every request.
* Dynamic routes that cannot be known ahead of time, making static pre-rendering impractical.
* Authentication-dependent content, where access and rendering vary based on the user’s session or permissions.
### Configuration
To configure your Next.js application for use with Sevalla:
* Enable the `output: 'standalone'` setting in your `next.config.js` file. This option generates an optimized, self-contained production build that includes only the minimal files needed to run your application.
```javascript theme={null}
// next.config.js
module.exports = {
output: 'standalone',
};
```
* Use Next.js Image Optimization and configure the appropriate image loader to ensure efficient and high-quality asset delivery.
* Use opt-in caching with the `use cache` directive for dynamic content.
* Enable compression and set appropriate caching headers to improve performance.
### Containerization
#### Dockerfile
The build for [Dockerfiles](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. The following is an example Dockerfile for Next.js:
```javascript expandable theme={null}
# Dockerfile for Next.js on Sevalla
# Stage 1: Dependencies
FROM node:lts-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
# Stage 2: Builder
FROM node:lts-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Stage 3: Runner
FROM node:lts-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy necessary files
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]
```
#### Nixpacks
You can customize the [Nixpacks](https://docs.sevalla.com/applications/build-options/nixpacks) build process by defining a `nixpacks.toml` file and using [Nixpacks-specific environment variables](https://nixpacks.com/docs/configuration/environment). This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.
The following is an example `nixpacks.toml` configuration:
```typescript theme={null}
[phases.setup]
nixPkgs = ["nodejs", "yarn"]
[phases.install]
cmds = ["yarn install --frozen-lockfile"]
[phases.build]
cmds = ["yarn build"]
[start]
cmd = "yarn start"
```
Nixpacks will automatically detect your project's lock file and select the appropriate package manager during deployment.
Additionally, you can specify the [Node.js version](https://nixpacks.com/docs/providers/node) used during the build by setting the `NIXPACKS_NODE_VERSION`[ environment variable](https://nixpacks.com/docs/providers/node#:~:text=Setting%20the%20NIXPACKS_NODE_VERSION%20environment%20variable).
#### Buildpacks
If you're using [Buildpacks](https://docs.sevalla.com/applications/build-options/buildpacks), you cannot modify the underlying build phases directly or control dependencies. You must rely on the runtime environment that Buildpacks detects.
You can influence the build process by adjusting the `build` script in your `package.json`. Buildpacks will run whatever command you specify under the build script. For example, the standard command used to compile a Next.js application is:
```javascript theme={null}
"build": "next build"
```
You can also add additional logic before the build runs, for example:
```javascript theme={null}
"build": "echo \"Hi mom!\" && next build"
```
### CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your Next.js application, we recommend the following best practices:
* [Enable the CDN](https://docs.sevalla.com/applications/cdn) for all production applications to ensure faster global delivery and reduced latency.
* Use the Next.js `` component to take advantage of built-in image optimization and responsive delivery.
* [Purge the CDN cache](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after deploying critical updates to guarantee that users receive the latest content.
* Next.js automatically versions built assets in `_next/static/`, this ensures that static assets are uniquely hashed and safe to cache indefinitely.
* Organize static files in the `public/` directory, allowing the CDN to efficiently serve commonly accessed assets.
### Edge caching
[Edge caching](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your Next.js application, we recommend the following best practices:
* Use the `use cache` directive for opt-in caching, avoiding implicit caching behaviors.
* Select appropriate `cacheLife` profiles based on how frequently your content changes.
* Use `updateTag()` in Server Actions to immediately update cached content while maintaining read-your-writes consistency.
* Use `revalidateTag()` with the required `cacheLife` profile to refresh cache selectively.
* Set appropriate `Cache-Control` headers for API routes to balance speed with accuracy.
* Combine Edge Caching with the CDN for a comprehensive, high-performance caching strategy.
* Monitor cache efficiency using Cloudflare headers (e.g., `cf-cache-status`) to track hit rates.
* Cache individual functions for more granular control over which parts of your application are cached.
Next.js 16 changes caching from implicit to opt-in, with the `use cache` directive.
#### `Cache-Control`
With Sevalla’s Cloudflare integration, Cache-Control headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your Next.js application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets (e.g., files in `_next/static/`), allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user's browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
#### Opt-in caching with `use cache`
```javascript theme={null}
// src/app/products/page.tsx
import { cacheLife } from "next/cache";
export default async function ProductsPage() {
"use cache";
cacheLife("hours"); // Built-in profile: seconds, minutes, hours, days, weeks, max
const products = await fetchProducts();
return (
{products.map((product) => (
{product.name}
))}
);
}
```
**Custom cache profiles**
```javascript theme={null}
// next.config.mjs
export default {
output: "standalone",
cacheLife: {
product: {
stale: 3600, // 1 hour
revalidate: 86400, // 1 day
expire: 604800, // 1 week
},
},
};
```
```javascript theme={null}
// src/app/products/page.tsx
export default async function ProductsPage() {
"use cache";
cacheLife("product"); // Use custom profile
const products = await fetchProducts();
return {/* ... */}
;
}
```
#### Caching individual functions
You can cache specific functions instead of entire components:
```javascript theme={null}
// src/lib/data.ts
import { cacheLife } from "next/cache";
export async function getPost(slug: string) {
"use cache";
cacheLife("hours");
const post = await db.query("SELECT * FROM posts WHERE slug = $1", [slug]);
return post;
}
```
```javascript theme={null}
// src/app/blog/[slug]/page.tsx
import { getPost } from "@/lib/data";
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map((post) => ({ slug: post.slug }));
}
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await getPost(slug); // Cached function
return {post.content};
}
```
#### API routes with edge caching
```javascript theme={null}
// src/app/api/products/route.ts
export async function GET() {
const products = await fetchProducts();
return Response.json(products, {
headers: {
"Cache-Control": "public, s-maxage=3600",
},
});
}
```
#### Cache invalidation APIs
Next.js 16 introduces new cache invalidation APIs:
`revalidateTag()`**- Now requires cacheLife profile:**
```javascript theme={null}
// src/app/api/revalidate/route.ts
import { revalidateTag } from "next/cache";
export async function POST(request: Request) {
const { tag, secret } = await request.json();
if (secret !== process.env.REVALIDATION_SECRET) {
return Response.json({ message: "Invalid secret" }, { status: 401 });
}
try {
// Next.js 16: Second parameter (cacheLife profile) is required
revalidateTag(tag, "hours");
return Response.json({ revalidated: true });
} catch (err) {
return Response.json({ message: "Error revalidating" }, { status: 500 });
}
}
```
`updateTag()`**- New server actions-only API:**
```javascript theme={null}
// src/app/actions.ts
"use server";
import { updateTag } from "next/cache";
export async function updateProduct(productId: string, data: any) {
// Update database
await db.query("UPDATE products SET ... WHERE id = $1", [productId]);
// Expire cache and immediately refresh data (read-your-writes)
await updateTag(`product-${productId}`, "hours");
return { success: true };
}
```
`refresh()`**- New server actions-only API:**
```javascript theme={null}
// src/app/actions.ts
"use server";
import { refresh } from "next/cache";
export async function refreshData() {
// Refreshes only uncached data without touching cache layer
refresh();
return { success: true };
}
```
`revalidatePath()`**- Still available:**
```javascript theme={null}
// src/app/api/revalidate/route.ts
import { revalidatePath } from "next/cache";
export async function POST(request: Request) {
const { path, secret } = await request.json();
if (secret !== process.env.REVALIDATION_SECRET) {
return Response.json({ message: "Invalid secret" }, { status: 401 });
}
try {
revalidatePath(path);
return Response.json({ revalidated: true });
} catch (err) {
return Response.json({ message: "Error revalidating" }, { status: 500 });
}
}
```
### Healthchecks and graceful shutdown
Ensure your application remains available during deployments by implementing health checks and graceful shutdown strategies:
* Always implement [health checks](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
* Finish in-flight requests before terminating processes.
* Set a shutdown timeout (recommended: 30 seconds).
* Close connections cleanly (e.g., database pools, Redis) to prevent resource leaks.
* Use a custom server if advanced shutdown control is needed.
* Test deployments in staging with monitoring scripts to validate health checks and shutdown behavior.
#### Basic health check
```javascript theme={null}
// src/app/api/health/route.ts
export async function GET() {
return Response.json(
{ status: "ok", timestamp: new Date().toISOString() },
{ status: 200 }
);
}
```
#### Separate readiness and liveliness health checks
```javascript theme={null}
// src/app/api/health/ready/route.ts
// Readiness: Is the app ready to receive traffic?
import { pool } from "@/lib/db";
export async function GET() {
try {
// Check critical dependencies
await pool.query("SELECT 1");
return Response.json({ ready: true }, { status: 200 });
} catch (error) {
return Response.json(
{ ready: false, error: "Database unavailable" },
{ status: 503 }
);
}
}
```
#### Basic graceful shutdown
```javascript theme={null}
// src/server.ts (if using custom server)
import { createServer } from "http";
import { parse } from "url";
import next from "next";
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
const PORT = parseInt(process.env.PORT || "3000", 10);
app.prepare().then(() => {
const server = createServer((req, res) => {
const parsedUrl = parse(req.url!, true);
handle(req, res, parsedUrl);
});
server.listen(PORT, () => {
console.log(`> Ready on http://localhost:${PORT}`);
});
// Graceful shutdown
const gracefulShutdown = (signal: string) => {
console.log(`Received ${signal}, starting graceful shutdown...`);
server.close(() => {
console.log("HTTP server closed");
process.exit(0);
});
// Force shutdown after 30 seconds
setTimeout(() => {
console.error("Forced shutdown after timeout");
process.exit(1);
}, 30000);
};
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
});
```
### Multi-tenancy
Sevalla fully supports multi-tenancy. You can build multi-tenant Next.js applications using [wildcard domains](https://docs.sevalla.com/applications/domains), allowing you to serve multiple tenants from separate subdomains efficiently and securely. Use the following best practices for multi-tenancy on Sevalla with your Next.js application:
* Use wildcard domains to serve subdomain-based tenants (e.g., `tenant1.app.com`).
* Add custom domains individually for tenants who have their own domains.
* Cache tenant data to reduce database queries and improve performance.
* Validate tenant existence before rendering pages to prevent errors or unauthorized access.
* Isolate tenant data in the database using separate schemas or a `tenant_id` column.
* Leverage free SSL certificates, which are automatically provided for both wildcard and custom domains.
#### Next.js 16 multi-tenant implementation
**Extract tenant from subdomain:**
```javascript theme={null}
// src/proxy.ts (renamed from middleware.ts in Next.js 16)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export async function proxy(request: NextRequest) {
const hostname = request.headers.get("host") || "";
const subdomain = hostname.split(".")[0];
// Skip for main domain
if (subdomain === "www" || subdomain === "yourdomain") {
return NextResponse.next();
}
// Add tenant to headers
const response = NextResponse.next();
response.headers.set("x-tenant-id", subdomain);
return response;
}
```
Next.js 16 renamed `middleware.ts` to `proxy.ts` and the exported function to `proxy()`.
**Use tenant in pages:**
```javascript theme={null}
// src/app/page.tsx
import { headers } from "next/headers";
export default async function HomePage() {
const headersList = await headers();
const tenantId = headersList.get("x-tenant-id");
const tenant = await getTenantData(tenantId);
return (
Welcome to {tenant.name}
);
}
```
**Tenant-specific data:**
```javascript theme={null}
// src/lib/tenant.ts
import { pool } from "./db";
export async function getTenantData(tenantId: string | null) {
if (!tenantId) return null;
const result = await pool.query(
"SELECT * FROM tenants WHERE subdomain = $1",
[tenantId]
);
return result.rows[0] || null;
}
```
#### Custom domains per tenant
Allow tenants to use their own domains (e.g., `customdomain.com` → tenant data).
**Map custom domains to tenants:**
```javascript theme={null}
// src/proxy.ts
export async function proxy(request: NextRequest) {
const hostname = request.headers.get("host") || "";
const tenant = await getTenantByDomain(hostname);
const response = NextResponse.next();
response.headers.set("x-tenant-id", tenant?.id || hostname.split(".")[0]);
return response;
}
```
## Static Site Hosting
Static Site Generation (SSG) pre-renders all pages as static HTML files at build time, delivering fast and reliable performance. Use SSG when your site includes:
* Content that changes infrequently, such as blog posts, documentation, or product catalogs.
* Pages that can be pre-rendered for all users without personalization.
* Requirements for maximum performance and minimal hosting costs.
* A global audience, as static pages benefit from fast CDN distribution.
### Configuration
To deploy a fully static Next.js site on Sevalla, make sure to include the following configuration in your `next.config.mjs` file:
* `output: 'export'` generates fully static HTML, CSS, and JS files for deployment to any static hosting. This generates all built assets to the `out` folder by default, unless you override this setting in the `next.config.mjs` file.
* `images.unoptimized: true` disables Next.js image optimization, which is required for pure static exports.
* `trailingSlash: true` ensures all routes include a trailing slash, which helps maintain a consistent URL structure and meet static hosting requirements.
```javascript theme={null}
// next.config.mjs
export default {
// Enable static export mode to generate pure HTML/CSS/JS files
output: 'export',
// Add a trailing slash to all URLs (e.g., /about/ instead of /about)
trailingSlash: true,
images: {
// Required for static export; disables automatic Next.js image optimization
unoptimized: true,
},
};
```
### Redirects
To apply custom [redirect rules](https://docs.sevalla.com/static-sites/redirects), add a `_redirects` file containing your redirects to your repository's root directory. Sevalla will automatically parse the file’s contents and apply the custom redirect rules.
### Pretty URLs
In Sevalla, you can enable [Pretty URLs](https://docs.sevalla.com/static-sites/settings#redirects) to standardize your site’s URLs and improve SEO. This feature automatically enforces a trailing slash on the path of static site requests using a 301 redirect.
# Nuxt
Source: https://docs.sevalla.com/quick-starts/javascript/nuxt
This guide explains how to deploy a basic Nuxt.js site to Sevalla.
[Nuxt](https://nuxt.com/) is a high-performance, open-source framework built on Vue.js. It provides a powerful environment for building full-stack applications, static sites, and server-rendered experiences with minimal configuration.
Nuxt can be deployed using either Application Hosting (SSR) or Static Site Hosting (SSG). The primary difference lies in how you configure the `nuxt.config.ts` file. If not all pages are prerendered, you should use Application Hosting; otherwise, you should use Static Site Hosting.
## Application Hosting
Choose Application Hosting (Server-Side Rendering) when your application requires server-side logic or dynamic behavior that static files cannot provide. SSR is ideal when your site includes:
* Personalized user experiences, such as dashboards and profiles.
* Real-time or frequently changing data that must be fetched on every request.
* Dynamic routes that cannot be known ahead of time, making static pre-rendering impractical.
* Authentication-dependent content, where access and rendering vary based on the user’s session or permissions.
### Configuration
To configure your Nuxt application for Sevalla, we recommend you follow these best practices:
* Use Nitro’s built-in caching (`defineCachedEventHandler`) for expensive operations.
* Apply Nuxt Route Rules for static generation and edge caching.
* Use Nuxt Image for optimized image delivery.
* Enable compression in your Nitro config.
* Prerender pages that don’t require SSR.
Nuxt requires `runtimeConfig` for handling environment variables, ensuring they are properly injected and kept server-only unless explicitly exposed.
The following is an example `nuxt.config.ts` file for deploying a Nuxt.js app on Sevalla:
```javascript theme={null}
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
preset: 'node-server',
compressPublicAssets: true,
}
})
```
### Containerization
#### Dockerfile
The build for [Dockerfiles](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. The following is an example Dockerfile for Nuxt.js:
```javascript theme={null}
FROM node:lts-alpine
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
COPY . .
RUN npm run build
EXPOSE 3000
ENV PORT=3000
ENV HOST=0.0.0.0
CMD ["npm", "start"]
```
#### Nixpacks
You can customize the [Nixpacks](https://docs.sevalla.com/applications/build-options/nixpacks) build process by defining a `nixpacks.toml` file and using [**Nixpacks-specific environment variables**](https://nixpacks.com/docs/configuration/environment). This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.
The following is an example `nixpacks.toml` configuration:
```javascript theme={null}
# nixpacks.toml
# Override phases
[phases.setup]
nixPkgs = ["nodejs-22_x", "pnpm"]
[phases.install]
cmds = ["pnpm install --frozen-lockfile"]
[phases.build]
cmds = ["pnpm run build"]
# Set start command
[start]
cmd = "node .output/server/index.mjs"
# Environment variables available at build time
[variables]
NODE_ENV = "production"
```
Nixpacks will automatically detect your project’s lock file and select the appropriate package manager during deployment.
Additionally, you can specify the [**Node.js version**](https://nixpacks.com/docs/providers/node) used during the build by setting the `NIXPACKS_NODE_VERSION`[**environment variable**](https://nixpacks.com/docs/providers/node#:~:text=Setting%20the%20NIXPACKS_NODE_VERSION%20environment%20variable).
#### Buildpacks
If you’re using [Buildpacks](https://docs.sevalla.com/applications/build-options/buildpacks), you cannot modify the underlying build phases directly or control dependencies. You must rely on the runtime environment that Buildpacks detects.
You can influence the build process by adjusting the `build` script in your `package.json`. Buildpacks will run whatever command you specify under the build script. For example, the standard command used to compile a Nuxt.js application is:
```javascript theme={null}
"build": "nuxt build"
```
You can also add additional logic before the build runs, for example:
```javascript theme={null}
"build": "echo \"Hi mom!\" && nuxt build"
```
### CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your Nuxt.js application, we recommend the following best practices:
* [Enable the CDN](https://docs.sevalla.com/applications/cdn) for all production applications to ensure global, low-latency delivery.
* Use the `` component for automatic image optimization and responsive formats.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [Purge CDN cache](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after critical deployments to ensure users receive updated content.
* Rely on Nuxt’s versioned assets in the `_nuxt/ `directory, which are safe to cache indefinitely.
* Store static files in the `public/` directory, allowing the CDN to serve them efficiently.
### Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your Nuxt.js application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers on server-rendered pages to control caching behavior.
* Combine edge caching with the CDN to cover both dynamic and static assets.
* Monitor cache efficiency using the `cf-cache-status` header returned by Cloudflare.
Fully static pages are cached indefinitely by default, providing maximum performance.
Edge caching works best when you combine static and dynamic content with proper cache headers. Below are strategies to optimize your Nuxt.js application on Sevalla for edge caching.
#### `Cache-Control`
With Sevalla’s Cloudflare integration, `Cache-Control` headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your Nuxt.js application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets (e.g., files in `.output/public/_nuxt/`), allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
For example:
```javascript theme={null}
// server/api/public-data.ts
export default defineEventHandler(async (event) => {
const data = await fetchPublicData();
setResponseHeader(event, "Cache-Control", "public, s-maxage=3600");
return data;
});
```
#### Server route caching with Nitro
Nuxt.js uses Nitro's caching capabilities for server routes:
```javascript theme={null}
// server/api/products.ts
export default defineCachedEventHandler(
async (event) => {
const products = await fetchProducts();
return products;
},
{
maxAge: 60 * 60, // Cache for 1 hour
name: "products",
getKey: () => "all-products",
}
);
```
**Custom cache with more control**
```javascript theme={null}
// server/api/products.ts
export default defineEventHandler(async (event) => {
const cached = await useStorage("cache").getItem("products");
if (cached) {
return cached;
}
const products = await fetchProducts();
await useStorage("cache").setItem("products", products, {
ttl: 60 * 60, // 1 hour
});
return products;
});
```
#### Route rules for page caching
You can use route rules to cache specific pages:
```javascript theme={null}
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// Static page generated at build time
"/about": { prerender: true },
// SWR (Stale-While-Revalidate) - serve cached, update in background
"/blog/**": { swr: 3600 },
// ISR (Incremental Static Regeneration)
"/products/**": { isr: 3600 },
// Disable caching for dynamic content
"/api/user/**": { cache: false },
},
});
```
```javascript theme={null}
{{ post?.title }}
```
#### Cache Invalidation
Nuxt.js provides cache invalidation through Nitro's storage layer:
**Clear specific cache entry:**
```javascript theme={null}
// server/api/revalidate.post.ts
export default defineEventHandler(async (event) => {
const { key, secret } = await readBody(event);
const config = useRuntimeConfig();
if (secret !== config.revalidationSecret) {
throw createError({
statusCode: 401,
message: "Invalid secret",
});
}
try {
// Clear specific cache entry
await useStorage("cache").removeItem(key);
return { revalidated: true };
} catch (err) {
throw createError({
statusCode: 500,
message: "Error revalidating",
});
}
});
```
**Clear all cache:**
```javascript theme={null}
// server/api/clear-cache.post.ts
export default defineEventHandler(async (event) => {
const { secret } = await readBody(event);
const config = useRuntimeConfig();
if (secret !== config.revalidationSecret) {
throw createError({
statusCode: 401,
message: "Invalid secret",
});
}
try {
// Clear all cache
await useStorage("cache").clear();
return { cleared: true };
} catch (err) {
throw createError({
statusCode: 500,
message: "Error clearing cache",
});
}
});
```
**Programmatic cache invalidation:**
```javascript theme={null}
// server/utils/cache.ts
export async function invalidateProductCache(productId: string) {
await useStorage("cache").removeItem(`product-${productId}`);
}
export async function invalidateAllProducts() {
const keys = await useStorage("cache").getKeys("product-");
await Promise.all(keys.map((key) => useStorage("cache").removeItem(key)));
}
```
### Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
* Close connections cleanly (e.g., database pools, Redis) to prevent resource leaks.
* Test deployments in staging with monitoring scripts to validate health checks.
**Basic health check**
```javascript theme={null}
// server/api/health.ts
export default defineEventHandler(() => {
return {
status: "ok",
timestamp: new Date().toISOString(),
};
});
```
### Multi-tenancy
Sevalla fully supports multi-tenancy. You can build multi-tenant Nuxt.js applications using [**wildcard domains**](https://docs.sevalla.com/applications/domains), allowing you to serve multiple tenants from separate subdomains efficiently and securely. Use the following best practices for multi-tenancy on Sevalla with your Nuxt.js application:
* Use wildcard domains to serve subdomain-based tenants (e.g., `tenant1.app.com`).
* Add custom domains individually for tenants who have their own domains.
* Cache tenant data to reduce database queries and improve performance.
* Validate tenant existence before rendering pages to prevent errors or unauthorized access.
* Isolate tenant data in the database using separate schemas or a `tenant_id` column.
* Leverage free SSL certificates, which are automatically provided for both wildcard and custom domains.
#### **Nuxt.js multi-tenant implementation**
Below is a reference architecture for extracting tenant information from the hostname and injecting it into Nuxt's request lifecycle.
**Extract tenant from subdomain using middleware:**
```javascript theme={null}
// server/middleware/tenant.ts
export default defineEventHandler((event) => {
const host = getRequestHeader(event, "host") || "";
const subdomain = host.split(".")[0];
// Skip for main domain
if (subdomain === "www" || subdomain === "yourdomain") {
return;
}
// Add tenant to event context
event.context.tenantId = subdomain;
});
```
**Use tenant in API routes:**
```javascript theme={null}
// server/api/tenant-info.ts
export default defineEventHandler(async (event) => {
const tenantId = event.context.tenantId;
if (!tenantId) {
return { error: "No tenant specified" };
}
const tenant = await getTenantData(tenantId);
return {
tenant: tenant.name,
subdomain: tenantId,
};
});
```
**Use tenant in pages:**
```javascript theme={null}
Welcome to {{ tenant?.tenant }}
```
**Tenant-specific data:**
```javascript theme={null}
// server/utils/tenant.ts
import { pool } from "./db";
export async function getTenantData(tenantId: string) {
const result = await pool.query(
"SELECT * FROM tenants WHERE subdomain = $1",
[tenantId]
);
return result.rows[0] || null;
}
```
#### Custom domains per tenant
Allow tenants to use their own domains (e.g., `customdomain.com` → tenant data).
**Map custom domains to tenants:**
```javascript theme={null}
// server/middleware/tenant.ts
export default defineEventHandler(async (event) => {
const host = getRequestHeader(event, "host") || "";
const tenant = await getTenantByDomain(host);
event.context.tenantId = tenant?.id || host.split(".")[0];
});
```
## [](https://docs.sevalla.com/quick-starts/javascript/astro#astro-multi-tenant-implementation)Static Site Hosting
Static Site Generation (SSG) pre-renders all pages as static HTML files at build time, delivering fast and reliable performance. Use SSG when your site includes:
* Content that changes infrequently, such as blog posts, documentation, or product catalogs.
* Pages that can be pre-rendered for all users without personalization.
* Requirements for maximum performance and minimal hosting costs.
* A global audience, as static pages benefit from fast CDN distribution.
### Configuration
Use `nuxt generate` to build and prerender your application using Nitro’s crawler. This command is similar to running `nuxt build` with `nitro.static` enabled (or `nuxt build --prerender`).
During generation, Nuxt builds your site, starts a temporary server, and automatically crawls pages beginning with `/` pre-rendering every reachable route.
```javascript theme={null}
npx nuxt generate
```
After the build completes, you can deploy the contents of `.output/public` to any static hosting provider, or preview the result locally using:
```javascript theme={null}
npx serve .output/public
```
For more information, refer to [Nuxt.js documentation](https://nuxt.com/docs/4.x/getting-started/prerendering#crawl-based-pre-rendering).
### Redirects
To apply custom [redirect rules](https://docs.sevalla.com/static-sites/redirects), add a `_redirects` file containing your redirects to your repository's root directory. Sevalla will automatically parse the file’s contents and apply the custom redirect rules.
### Pretty URLs
In Sevalla, you can enable [Pretty URLs](https://docs.sevalla.com/static-sites/settings#redirects) to standardize your site’s URLs and improve SEO. This feature automatically enforces a trailing slash on the path of static site requests using a 301 redirect.
# Object storage integration
Source: https://docs.sevalla.com/quick-starts/javascript/object-storage-integration
This guide explains how to use Object storage in Sevalla for your JavaScript/TypeScript applications.
Using [Sevalla’s object storage](https://docs.sevalla.com/object-storage/overview), powered by Cloudflare R2, with your JavaScript or TypeScript application provides secure, scalable, and persistent storage for files such as images, videos, documents, or application-generated assets. Its S3-compatible API allows seamless integration with popular JS/TS libraries, enabling easy programmatic access for uploads, downloads, and file management. This makes it ideal for handling user uploads, storing backend outputs, caching media, or serving assets to your frontend, all while keeping your data private and reliably accessible across deployments and application instances.
We recommend using the [AWS S3 SDK](https://www.npmjs.com/package/@aws-sdk/client-s3) for object storage, file uploads, and asset management in JavaScript/TypeScript applications.
## Installation
Install the required dependencies:
```bash theme={null}
npm install @aws-sdk/client-s3
```
* **@aws-sdk/client-s3**: AWS SDK v3 for S3 operations (modular and tree-shakeable).
Optional for advanced features:
```bash theme={null}
npm install @aws-sdk/s3-request-presigner # For pre-signed URLs
```
## Environment variables
Add the following [environment variables](https://docs.sevalla.com/applications/environment-variables) to your application from the [Object storage service details](https://docs.sevalla.com/object-storage/settings#details):
```env theme={null}
S3_REGION=your_region_here
S3_ACCESS_KEY_ID=your_access_key_here
S3_SECRET_ACCESS_KEY=your_secret_key_here
S3_BUCKET_NAME=your_bucket_name
S3_ENDPOINT=https://s3.sevalla.storage # Optional
```
## Setting up the client
```typescript theme={null}
// src/config/s3.ts
import { S3Client } from "@aws-sdk/client-s3";
const s3Client = new S3Client({
region: process.env.S3_REGION || "us-east-1",
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID || "",
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY || "",
},
endpoint: process.env.S3_ENDPOINT, // Optional
forcePathStyle: process.env.S3_ENDPOINT ? true : false,
});
export default s3Client;
```
**Note**: AWS SDK v3 uses modular imports, which means you only import the commands you need, resulting in smaller bundle sizes.
## Basic usage examples
### Upload a file
```typescript theme={null}
import { PutObjectCommand } from "@aws-sdk/client-s3";
import s3Client from "@src/config/s3";
const command = new PutObjectCommand({
Bucket: process.env.S3_BUCKET_NAME!,
Key: 'my-file-key.txt',
Body: buffer,
ContentType: data.mimetype,
// Optional
Metadata: {
uploadedBy: "user123",
originalName: data.filename,
},
});
await s3Client.send(command);
```
### Download a file
```typescript theme={null}
import { GetObjectCommand } from "@aws-sdk/client-s3";
import s3Client from "@src/config/s3";
const command = new GetObjectCommand({
Bucket: process.env.S3_BUCKET_NAME!,
Key: 'my-file-key.txt',
});
const response = await s3Client.send(command);
const str = await response.Body?.transformToString();
```
### Delete a file
```typescript theme={null}
import { DeleteObjectCommand } from "@aws-sdk/client-s3";
import s3Client from "@src/config/s3";
const command = new DeleteObjectCommand({
Bucket: process.env.S3_BUCKET_NAME!,
Key: 'my-file-key.txt',
});
await s3Client.send(command);
```
### List files in bucket
```typescript theme={null}
import { ListObjectsV2Command } from "@aws-sdk/client-s3";
import s3Client from "@src/config/s3";
const command = new ListObjectsV2Command({
Bucket: process.env.S3_BUCKET_NAME!,
Prefix: '',
MaxKeys: 100,
});
const response = await s3Client.send(command);
const files =
response.Contents?.map((item) => ({
key: item.Key,
size: item.Size,
lastModified: item.LastModified,
etag: item.ETag,
})) || [];
```
### Generate pre-signed URL (Temporary access)
```typescript theme={null}
import { GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import s3Client from "@src/config/s3";
const key = 'my-file-key.txt';
const expiresIn = 3600; // Default: 1 hour
const command = new GetObjectCommand({
Bucket: process.env.S3_BUCKET_NAME!,
Key: key,
});
// Generate a pre-signed URL valid for specified time
const url = await getSignedUrl(s3Client, command, { expiresIn });
```
## Advanced S3 operations
### Multi-part upload (Large files)
```typescript theme={null}
import { Upload } from "@aws-sdk/lib-storage";
import s3Client from "@src/config/s3";
async function uploadLargeFile(file: Buffer | Readable, key: string, mimetype: string) {
const parallelUploads3 = new Upload({
client: s3Client,
params: {
Bucket: process.env.S3_BUCKET_NAME!,
Key: key,
Body: file,
ContentType: mimetype
},
// Optional: concurrency configuration
queueSize: 4,
partSize: 1024 * 1024 * 5,
});
parallelUploads3.on("httpUploadProgress", (progress) => {
console.log(progress);
});
await parallelUploads3.done();
}
```
### Copy objects
```typescript theme={null}
import { CopyObjectCommand } from "@aws-sdk/client-s3";
async function copyFile(sourceKey: string, destinationKey: string) {
const command = new CopyObjectCommand({
Bucket: process.env.S3_BUCKET_NAME!,
CopySource: `${process.env.S3_BUCKET_NAME}/${sourceKey}`,
Key: destinationKey,
});
await s3Client.send(command);
}
```
### Get object metadata
```typescript theme={null}
import { HeadObjectCommand } from "@aws-sdk/client-s3";
async function getMetadata(key: string) {
const command = new HeadObjectCommand({
Bucket: process.env.S3_BUCKET_NAME!,
Key: key,
});
const response = await s3Client.send(command);
return {
contentType: response.ContentType,
contentLength: response.ContentLength,
lastModified: response.LastModified,
metadata: response.Metadata,
etag: response.ETag,
};
}
```
### Set object ACL (Access control)
```typescript theme={null}
import { PutObjectAclCommand } from "@aws-sdk/client-s3";
async function makePublic(key: string) {
const command = new PutObjectAclCommand({
Bucket: process.env.S3_BUCKET_NAME!,
Key: key,
ACL: "public-read",
});
await s3Client.send(command);
}
```
## Best Practices
1. **Use streaming for large files** - Don't load entire files into memory
2. **Implement retry logic** - S3 operations can fail, implement exponential backoff
3. **Use pre-signed URLs** - For direct client uploads/downloads, reduce server load
4. **Set appropriate CORS** - Configure bucket CORS if accessing from browser
5. **Use multipart upload** - For files > 100MB
6. **Implement file validation** - Check file types and sizes before upload
7. **Use proper naming conventions** - Organize files with prefixes (folders)
8. **Enable versioning** - For important files, enable S3 versioning
9. **Monitor storage costs** - Use lifecycle policies to move/delete old files
10. **Implement error handling** - Always wrap S3 operations in try-catch blocks
11. **Use content types** - Always set the correct ContentType when uploading
12. **Secure credentials** - Never commit S3 credentials, use environment variables
## Common Issues
### Access Denied Errors
If you get "Access Denied" errors:
* Verify access key and secret key are correct
* Verify the bucket policy allows the operations
* Ensure credentials match the service details
### Connection Timeout
If uploads/downloads timeout:
* Verify S3\_ENDPOINT is correct
* Increase timeout in S3 client config:
```typescript theme={null}
const s3Client = new S3Client({
region: process.env.S3_REGION,
credentials: {
/*...*/
},
requestHandler: {
connectionTimeout: 30000, // 30 seconds
requestTimeout: 300000, // 5 minutes
},
});
```
### Large File Upload Issues
For large files:
* Use multipart upload for files > 100MB
* Implement progress tracking
* Handle network interruptions with retry logic
### CORS Errors (Browser Uploads)
Fine-tune your bucket CORS configuration on the Sevalla dashboard.
## Performance Tips
1. **Parallelize uploads**:
```typescript theme={null}
const uploadPromises = files.map((file) => uploadFile(file));
await Promise.all(uploadPromises);
```
2. **Cache frequently accessed files**:
```typescript theme={null}
// Use Redis to cache small files
const cached = await redis.get(`s3:${key}`);
if (cached) {
return Buffer.from(cached, "base64");
}
```
3. **Implement pagination** for listing:
```typescript theme={null}
async function listAllObjects(prefix: string) {
const allObjects = [];
let continuationToken;
do {
const command = new ListObjectsV2Command({
Bucket: process.env.S3_BUCKET_NAME!,
Prefix: prefix,
ContinuationToken: continuationToken,
});
const response = await s3Client.send(command);
allObjects.push(...(response.Contents || []));
continuationToken = response.NextContinuationToken;
} while (continuationToken);
return allObjects;
}
```
## Security Best Practices
1. **Enable encryption at rest** - Use server-side encryption:
```typescript theme={null}
const command = new PutObjectCommand({
Bucket: process.env.S3_BUCKET_NAME!,
Key: key,
Body: buffer,
ServerSideEncryption: "AES256",
});
```
2. **Scan files for viruses** before storing
3. **Implement rate limiting** for upload endpoints
4. **Validate file types** based on content, not just extension
5. **Use signed URLs** for sensitive content
# Puppeteer
Source: https://docs.sevalla.com/quick-starts/javascript/puppeteer
This guide explains how to deploy a basic Puppeteer site to Sevalla.
[Puppeteer](https://pptr.dev/) is a Node.js library that provides a high-level API for controlling headless Chrome and Chromium browsers. It enables developers to automate browser tasks such as generating PDFs, taking screenshots, scraping websites, running end-to-end tests, and simulating user interactions. With its powerful DevTools integration, Puppeteer offers precise control over page behavior, network requests, and rendering, making it a popular choice for automation, testing, and web content processing.
Puppeteer can only be used on Application Hosting; it cannot be deployed as a static site.
## Configuration
We recommend the following best practices when using Puppeteer with Sevalla:
* Always make sure your processes terminate cleanly by calling `process.exit(0)`
* Implement robust error handling and logging to prevent unwanted crashes.
* Use an external job queue (e.g., Redis, BullMQ) for reliable background processing.
* Add detailed logging to help troubleshoot Puppeteer and browser-related issues.
* Always close browser and page instances to avoid memory leaks and runaway processes.
* Run Puppeteer with the `--no-sandbox` and `--disable-setuid-sandbox` flags in production.
* Test all Puppeteer scripts locally before deploying to Sevalla.
When deploying with a Dockerfile, make sure all required Chrome/Chromium system dependencies are installed.
For generated output, such as PDFs or screenshots, use Sevalla's [object storage](https://docs.sevalla.com/object-storage/overview) or integrate an external storage service like S3.
## Containerization
### Dockerfile
The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. We recommend using a multi-stage build approach with three stages:
1. `deps` - Install Chromium and Node.js dependencies.
2. `builder` - Build TypeScript code.
3. `runner` - Final production image with minimal size.
Example Dockerfile:
```go expandable theme={null}
# Stage 1: Dependencies
FROM node:lts-alpine AS deps
WORKDIR /app
# Install Chromium and system dependencies
RUN apk add --no-cache \
chromium \
nss \
freetype \
harfbuzz \
ca-certificates \
ttf-freefont
# Configure Puppeteer to use system Chromium
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
COPY package*.json ./
RUN npm ci
# Stage 2: Builder
FROM node:lts-alpine AS builder
WORKDIR /app
RUN apk add --no-cache \
chromium \
nss \
freetype \
harfbuzz \
ca-certificates \
ttf-freefont
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Stage 3: Runner (Production)
FROM node:lts-alpine AS runner
WORKDIR /app
# Install Chromium and dependencies
RUN apk add --no-cache \
chromium \
nss \
freetype \
harfbuzz \
ca-certificates \
ttf-freefont \
&& rm -rf /var/cache/apk/*
ENV NODE_ENV=production
ENV PORT=3000
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
# Create non-root user for security
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 puppeteeruser
COPY --from=builder --chown=puppeteeruser:nodejs /app/dist ./dist
COPY --from=builder --chown=puppeteeruser:nodejs /app/package*.json ./
COPY --from=builder --chown=puppeteeruser:nodejs /app/node_modules ./node_modules
USER puppeteeruser
EXPOSE 3000
CMD ["node", "dist/server.js"]
```
This Dockerfile includes the following key features:
1. **Alpine Linux Base**
* Uses `node:lts-alpine` for minimal image size
* Includes only essential Chromium dependencies
* Results in smaller, faster deployments
2. **System Chromium**
* Installs Chromium via `apk` package manager
* Avoids duplicate browser downloads
* More reliable than Puppeteer's bundled Chromium
* Environment variables configure Puppeteer to use system Chromium:
```javascript theme={null}
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
```
3. **Security**
* Runs as non-root user (`puppeteeruser`)
* Follows the least-privilege principle
* Safer for production deployments
4. **Multi-stage Build**
1. Separates build dependencies from runtime
2. Reduces final image size
3. Only production dependencies in the final image
### Nixpacks
[Nixpacks](https://docs.sevalla.com/applications/build-options/nixpacks) automatically detects your project type and creates an optimized build plan. You can customize the **Nixpacks** build process by defining a `nixpacks.toml` file. This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.
The following is an example `nixpacks.toml` configuration:
```javascript theme={null}
[phases.setup]
nixPkgs = ["nodejs_lts", "chromium"]
[phases.install]
cmds = [
"npm ci"
]
[phases.build]
cmds = [
"npm run build",
"npx puppeteer browsers install chrome"
]
[start]
cmd = "node dist/server.js"
```
#### Build phases
**1. Setup phase**
```javascript theme={null}
[phases.setup]
nixPkgs = ["nodejs_lts", "chromium"]
```
* `nodejs_lts`: Installs the latest Node.js.
* `chromium`: Installs system-level Chromium browser and all necessary dependencies. This ensures Chrome/Chromium is available for Puppeteer without manual Dockerfile configuration.
**2. Install phase**
```javascript theme={null}
[phases.install]
cmds = ["npm ci"]
```
* `npm ci:` Performs a clean install using `package-lock.json`. This ensures deterministic, reproducible builds, and it is faster and more reliable than `npm install` for production.
**3. Build phase**
```javascript theme={null}
[phases.build]
cmds = [
"npm run build",
"npx puppeteer browsers install chrome"
]
```
* `npm run build`: Compiles TypeScript to JavaScript (outputs to `dist/` directory).
* `npx puppeteer browsers install chrome`: Downloads Chrome browser for Puppeteer.
* Both commands run sequentially during deployment.
**4. Start command**
```javascript theme={null}
[start]
cmd = "node dist/server.js"
```
* Starts the application by running the compiled JavaScript.
* Points to `dist/server.js` (adjust this if your entry point is different, e.g., `dist/index.js`).
# Redis integration
Source: https://docs.sevalla.com/quick-starts/javascript/redis-integration
This guide explains how to integrate Redis with your JavaScript/TypeScript applications in Sevalla.
Using Redis with your JavaScript application on Sevalla enhances performance by enabling fast in-memory data access, supports real-time features such as notifications or chat, and facilitates reliable background job processing, helping your app scale efficiently and handle high traffic.
This guide covers Redis integration for caching, real-time features, using `ioredis`, and background job processing with `bullmq`.
## Installation
Install the required dependencies:
```bash theme={null}
npm install ioredis dotenv
npm install -D @types/ioredis
```
* `ioredis`: High-performance Redis client for Node.js with full TypeScript support.
* `dotenv`: Load environment variables from `.env` file.
* `@types/ioredis`: TypeScript definitions for ioredis (usually not needed as ioredis has built-in types).
## Environment variables with dotenv
Add Redis configuration to your `.env` file:
```env theme={null}
# Redis Configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=yourpassword
REDIS_DB=0
# Or use Redis URL (alternative)
REDIS_URL=redis://:password@localhost:6379/0
```
Load environment variables at the top of your entry file:
```typescript theme={null}
// src/index.ts
import "dotenv/config";
// ... rest of your code
```
## Redis connection setup
Create a Redis client configuration:
```typescript theme={null}
// src/config/redis.ts
import Redis from "ioredis";
// Option 1: Using individual parameters
const redis = new Redis({
host: process.env.REDIS_HOST || "localhost",
port: Number(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
db: Number(process.env.REDIS_DB) || 0,
retryStrategy: (times) => {
const delay = Math.min(times * 50, 2000);
return delay;
},
maxRetriesPerRequest: 3,
});
// Option 2: Using Redis URL
const redisFromUrl = new Redis(
process.env.REDIS_URL || "redis://localhost:6379"
);
// Handle connection events
redis.on("connect", () => {
console.log("Redis client connected");
});
redis.on("error", (err) => {
console.error("Redis connection error:", err);
});
redis.on("ready", () => {
console.log("Redis client ready");
});
redis.on("close", () => {
console.log("Redis connection closed");
});
export default redis;
```
## Basic usage examples
### Simple key-value operations
```typescript theme={null}
import redis from "@src/config/redis";
// Set a value
const key = 'foo';
const { value, ttl } = request.body; // ttl in seconds
if (ttl) {
await redis.setex(key, ttl, JSON.stringify(value));
} else {
await redis.set(key, JSON.stringify(value));
}
// Get a value
const key = 'foo';
const value = await redis.get(key);
// Delete a value
const key = 'foo';
await redis.del(key);
```
### Caching database queries
```typescript theme={null}
import redis from "@src/config/redis";
import pool from "@src/config/database";
const id = '1234';
const cacheKey = `user:${id}`;
// Try to get from cache first
const cached = await redis.get(cacheKey);
if (cached) {
console.log("Cache hit");
return { source: "cache", user: JSON.parse(cached) }
}
// If not in cache, query database
console.log("Cache miss");
const result = await pool.query("SELECT * FROM users WHERE id = $1", [
id,
]);
const user = result.rows[0];
await redis.setex(cacheKey, 300, JSON.stringify(user));
return { source: "database", user };
// ---
// Invalidate cache when user is updated
const { name, email } = request.body;
const result = await pool.query(
"UPDATE users SET name = $1, email = $2 WHERE id = $3 RETURNING *",
[name, email, id]
);
// Invalidate cache
await redis.del(`user:${id}`);
```
### Pub/Sub Pattern
```typescript theme={null}
// src/services/pubsub.ts
import Redis from "ioredis";
// Create separate Redis clients for pub/sub
const publisher = new Redis({
host: process.env.REDIS_HOST || "localhost",
port: Number(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
});
const subscriber = new Redis({
host: process.env.REDIS_HOST || "localhost",
port: Number(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
});
// Subscribe to a channel
subscriber.subscribe("notifications", (err, count) => {
if (err) {
console.error("Failed to subscribe:", err);
} else {
console.log(`Subscribed to ${count} channel(s)`);
}
});
// Handle incoming messages
subscriber.on("message", (channel, message) => {
console.log(`Received message from ${channel}:`, message);
// Process the message
});
// Publish a message
export const publishNotification = async (message: string) => {
await publisher.publish("notifications", message);
};
export { publisher, subscriber };
```
### Rate limiting
```typescript theme={null}
// src/plugins/rateLimit.ts
import redis from "@src/config/redis";
interface RateLimitOptions {
max: number;
window: number; // seconds
}
const rateLimitPlugin = async (
server,
opts
) => {
server.addHook("onRequest", async (request, reply) => {
const ip = request.ip;
const key = `rate_limit:${ip}`;
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, opts.window);
}
if (current > opts.max) {
const ttl = await redis.ttl(key);
return reply.status(429).send({
error: "Too many requests",
retryAfter: ttl,
});
}
});
};
```
## Advanced Redis operations
### Hash operations
```typescript theme={null}
// Set multiple fields in a hash
await redis.hset("user:1000", "name", "John Doe", "email", "john@example.com");
// Get a single field
const name = await redis.hget("user:1000", "name");
// Get all fields
const user = await redis.hgetall("user:1000");
// Increment a field
await redis.hincrby("user:1000", "visits", 1);
```
### List operations
```typescript theme={null}
// Push to list
await redis.lpush("jobs", JSON.stringify({ id: 1, task: "send-email" }));
// Pop from list (blocking)
const job = await redis.brpop("jobs", 0); // Wait indefinitely
// Get list length
const length = await redis.llen("jobs");
```
### Set operations
```typescript theme={null}
// Add members to set
await redis.sadd("online_users", "user1", "user2", "user3");
// Check if member exists
const isMember = await redis.sismember("online_users", "user1");
// Get all members
const members = await redis.smembers("online_users");
// Remove member
await redis.srem("online_users", "user1");
```
### Sorted set operations
```typescript theme={null}
// Add members with scores
await redis.zadd("leaderboard", 100, "player1", 200, "player2", 150, "player3");
// Get top players (highest scores)
const topPlayers = await redis.zrevrange("leaderboard", 0, 9, "WITHSCORES");
// Get player rank
const rank = await redis.zrevrank("leaderboard", "player1");
// Increment score
await redis.zincrby("leaderboard", 10, "player1");
```
## Job queues with BullMQ
BullMQ is a robust, Redis-based job queue for Node.js. It is ideal for offloading heavy tasks (like sending emails, video processing, or generating reports) to background processes.
### Installation
```bash theme={null}
npm install bullmq
```
### Shared connection configuration
BullMQ manages its own connections (one for the queue, one for the worker, and one for blocking commands). It is best to share the connection options rather than a single client instance.
```typescript theme={null}
// src/config/queue-config.ts
import { ConnectionOptions } from 'bullmq';
import dotenv from 'dotenv';
dotenv.config();
export const connectionOptions: ConnectionOptions = {
host: process.env.REDIS_HOST || 'localhost',
port: Number(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
db: Number(process.env.REDIS_DB) || 0,
};
```
### 1. Defining a queue (Producer)
This code typically runs in your web server API (e.g., when a user signs up).
```typescript theme={null}
// src/queues/emailQueue.ts
import { Queue } from 'bullmq';
import { connectionOptions } from '../config/queue-config';
// Create a new queue instance
export const emailQueue = new Queue('email-sending', {
connection: connectionOptions
});
// Helper to add jobs
export const addEmailJob = async (email: string, subject: string) => {
await emailQueue.add('send-welcome', {
email,
subject,
timestamp: new Date()
}, {
attempts: 3, // Retry 3 times on failure
backoff: {
type: 'exponential', // Wait longer between retries
delay: 1000,
},
removeOnComplete: true // Auto-remove successful jobs
});
};
```
### 2. Processing jobs (Worker)
The worker processes jobs from the queue. In production, this often runs as a separate service or process.
```typescript theme={null}
// src/workers/emailWorker.ts
import { Worker, Job } from 'bullmq';
import { connectionOptions } from '../config/queue-config';
// Define the processor
const worker = new Worker('email-sending', async (job: Job) => {
console.log(`Processing job ${job.id} for ${job.data.email}`);
// Simulate heavy task (e.g., API call to SendGrid/SES)
await new Promise(resolve => setTimeout(resolve, 2000));
if (Math.random() < 0.1) throw new Error("Random mail server failure!");
return { sent: true, messageId: '12345' };
}, {
connection: connectionOptions,
concurrency: 5 // Process 5 jobs at the same time
});
// Event listeners for logging
worker.on('completed', (job) => {
console.log(`Job ${job.id} completed!`);
});
worker.on('failed', (job, err) => {
console.error(`Job ${job.id} failed: ${err.message}`);
});
export default worker;
```
### 3. Delayed jobs
You can schedule jobs to run in the future using the delay option. This relies on Redis keyspace notifications.
```typescript theme={null}
// Schedule a follow-up email 24 hours from now
await emailQueue.add('send-followup', {
userId: '123'
}, {
delay: 24 * 60 * 60 * 1000 // 24 hours in milliseconds
});
```
## Sevalla Redis service
To use Redis on Sevalla:
1. **Create a Redis service** in your Sevalla dashboard
2. **Copy the connection credentials** from the service details
3. **Add Redis environment variables** to your application:
```
REDIS_HOST=your-redis-host
REDIS_PORT=6379
REDIS_PASSWORD=your-password
```
Or use a single URL:
```
REDIS_URL=redis://:password@host:6379/0
```
4. **Deploy your application** - it will automatically connect to Redis
## Best practices
1. **Set appropriate TTLs** - Don't let cache grow indefinitely, use `SETEX` or `EXPIRE`
2. **Handle errors gracefully** - Always wrap Redis calls in try-catch blocks
3. **Close connections on shutdown** - Use `redis.quit()` in SIGTERM handler
4. **Use pipeline for multiple commands** - Reduce network round-trips:
```typescript theme={null}
const pipeline = redis.pipeline();
pipeline.set("key1", "value1");
pipeline.set("key2", "value2");
pipeline.get("key1");
const results = await pipeline.exec();
```
5. **Monitor memory usage** - Use `redis.info('memory')` to track memory
6. **Use appropriate data structures** - Choose the right Redis data type for your use case
7. **Implement cache invalidation** - Delete stale cache when data changes
8. **Use Redis for session storage** - Instead of memory-based sessions for horizontal scaling
9. **Set connection timeout** - Configure `connectTimeout` and `retryStrategy`
## Common issues
### Connection refused
If you get "connection refused" errors:
* Check that Redis is running: `redis-cli ping`
* Verify the host and port in your configuration
* Ensure the firewall allows connections on port 6379
* On Sevalla, verify the Redis service is running
### Authentication errors
If you get authentication errors:
* Verify the password is correct
* Check if Redis requires authentication: `redis-cli CONFIG GET requirepass`
* Ensure the password is set in the environment variables
### Memory issues
If Redis runs out of memory:
* Set `maxmemory` and `maxmemory-policy` in Redis config
* Use appropriate TTLs for cached data
* Monitor memory usage: `redis-cli INFO memory`
* Consider using Redis eviction policies
### Connection timeouts
For production, configure the retry strategy:
```typescript theme={null}
const redis = new Redis({
host: process.env.REDIS_HOST,
port: Number(process.env.REDIS_PORT),
password: process.env.REDIS_PASSWORD,
retryStrategy: (times) => {
const delay = Math.min(times * 50, 2000);
return delay;
},
connectTimeout: 10000,
maxRetriesPerRequest: 3,
});
```
## Performance tips
1. **Use pipelining for bulk operations**:
```typescript theme={null}
const pipeline = redis.pipeline();
for (let i = 0; i < 1000; i++) {
pipeline.set(`key:${i}`, `value:${i}`);
}
await pipeline.exec();
```
2. **Use SCAN instead of KEYS**:
```typescript theme={null}
// ❌ Bad - blocks Redis
const keys = await redis.keys("user:*");
// ✅ Good - non-blocking
const stream = redis.scanStream({ match: "user:*" });
stream.on("data", (keys) => {
// Process keys
});
```
3. **Use Redis transactions when needed**:
```typescript theme={null}
await redis.multi().incr("counter").expire("counter", 3600).exec();
```
4. **Enable automatic pipelining**:
```typescript theme={null}
const redis = new Redis({
host: process.env.REDIS_HOST,
enableAutoPipelining: true,
});
```
# Remix
Source: https://docs.sevalla.com/quick-starts/javascript/remix
This guide explains how to deploy a basic Remix site to Sevalla.
[Remix](https://remix.run/) is a full-stack, server-side web framework built on modern web standards and designed for fast, resilient, and highly interactive applications. Its core philosophy is to embrace the browser platform, using web APIs wherever possible, and to prioritize user experience through advanced routing, progressive enhancement, and optimized data loading patterns.
Remix can only be used on Application Hosting; it cannot be deployed as a static site.
We recommend the following best practices to get the best performance when using Remix on Sevalla:
* Use Remix loaders for efficient, server-side data fetching.
* Apply appropriate `Cache-Control` headers in loader responses to maximize CDN performance.
* Take advantage of Remix’s built-in prefetching to speed up client-side navigation.
* Use resource routes for API endpoints to simplify data access and caching.
## Containerization
### Dockerfile
The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. The following is an example Dockerfile for Remix:
```javascript expandable theme={null}
# Dockerfile for Remix on Sevalla
FROM node:lts-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:lts-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3000
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 remixuser
COPY --from=builder --chown=remixuser:nodejs /app/build ./build
COPY --from=builder --chown=remixuser:nodejs /app/package*.json ./
COPY --from=builder --chown=remixuser:nodejs /app/node_modules ./node_modules
USER remixuser
EXPOSE 3000
CMD ["npm", "start"]
```
### Nixpacks
You can customize the [**Nixpacks**](https://docs.sevalla.com/applications/build-options/nixpacks) build process by defining a `nixpacks.toml` file and using [**Nixpacks-specific environment variables**](https://nixpacks.com/docs/configuration/environment). This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.
The following is an example `nixpacks.toml` configuration:
```javascript theme={null}
[phases.setup]
nixPkgs = ["nodejs", "npm"]
[phases.install]
cmds = ["npm install --frozen-lockfile"]
[phases.build]
cmds = ["npm run build"]
[start]
cmd = "npm start"
```
Nixpacks will automatically detect your project’s lock file and select the appropriate package manager during deployment.
Additionally, you can specify the [**Node.js version**](https://nixpacks.com/docs/providers/node) used during the build by setting the `NIXPACKS_NODE_VERSION`[**environment variable**](https://nixpacks.com/docs/providers/node#:~:text=Setting%20the%20NIXPACKS_NODE_VERSION%20environment%20variable).
### Buildpacks
If you’re using [**Buildpacks**](https://docs.sevalla.com/applications/build-options/buildpacks), you cannot modify the underlying build phases directly or control dependencies. You must rely on the runtime environment that Buildpacks detects.
You can influence the build process by adjusting the `build` script in your `package.json`. Buildpacks will run whatever command you specify under the build script. For example, the standard command used to compile a Remix application is:
```javascript theme={null}
"build": "remix build"
```
You can also add additional logic before the build runs, for example:
```javascript theme={null}
"build": "echo \"Hi mom!\" && remix build"
```
## [****](https://docs.sevalla.com/quick-starts/javascript/astro#cdn)**CDN**
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your Remix application, we recommend the following best practices:
* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications to ensure global, low-latency delivery.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after critical deployments to ensure users receive updated content.
* Rely on Remix's versioned assets in the `build/ `directory, which are safe to cache indefinitely.
* Store static files in the `public/` directory, allowing the CDN to serve them efficiently.
### Image optimization
```javascript theme={null}
// app/routes/_index.tsx
export default function Index() {
return (
);
}
```
### Static assets
Place static assets in the `public/` directory:
```javascript theme={null}
public/
├── images/
├── fonts/
└── favicon.ico
```
Remix automatically serves these with optimal caching headers.
## Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your Remix application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.
* Use Remix's `useFetcher` for client-side revalidation.
### `Cache-Control`
With Sevalla’s Cloudflare integration,`Cache-Control`headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your Remix application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
### `Cache-Control` headers for loaders
```javascript theme={null}
// app/routes/api.public-data.ts
import type { LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
export async function loader({ request }: LoaderFunctionArgs) {
const data = await fetchPublicData();
return json(data, {
headers: {
"Cache-Control": "public, max-age=3600, s-maxage=3600",
},
});
}
```
### Loader caching with headers
```javascript theme={null}
// app/routes/products._index.tsx
import type { LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
export async function loader({ request }: LoaderFunctionArgs) {
const products = await fetchProducts();
return json(products, {
headers: {
"Cache-Control":
"public, max-age=60, s-maxage=3600, stale-while-revalidate=86400",
},
});
}
export default function Products() {
const products = useLoaderData();
return (
{products.map((product) => (
{product.name}
))}
);
}
```
### Resource routes with caching
```javascript theme={null}
// app/routes/api.products.ts
import type { LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
export async function loader({ request }: LoaderFunctionArgs) {
const products = await fetchProducts();
return json(products, {
headers: {
"Cache-Control": "public, s-maxage=3600, stale-while-revalidate=86400",
},
});
}
```
### Client-side revalidation
```javascript theme={null}
// app/routes/blog.$slug.tsx
import { useFetcher } from "@remix-run/react";
import { useEffect } from "react";
export default function BlogPost() {
const fetcher = useFetcher();
useEffect(() => {
// Revalidate on focus
const handleFocus = () => {
fetcher.load(window.location.pathname);
};
window.addEventListener("focus", handleFocus);
return () => window.removeEventListener("focus", handleFocus);
}, [fetcher]);
return {/* ... */};
}
```
## Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
* Close connections cleanly (e.g., database pools, Redis) to prevent resource leaks.
* Test deployments in staging with monitoring scripts to validate health checks.
### Basic health check
```javascript theme={null}
// app/routes/api.health.ts
import type { LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
export async function loader({ request }: LoaderFunctionArgs) {
return json(
{ status: "ok", timestamp: new Date().toISOString() },
{ status: 200 }
);
}
```
## Graceful shutdown
Remix provides automatic graceful shutdown when using `remix-serve`, but you can add custom cleanup logic, such as closing database connections, by handling `SIGTERM` and `SIGINT` yourself. The example below demonstrates how to shut down a PostgreSQL connection pool during termination:
```javascript theme={null}
// app/lib/db.server.ts
import { Pool } from "pg";
export const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20,
idleTimeoutMillis: 30000,
});
// Graceful pool shutdown
const gracefulPoolShutdown = async () => {
console.log("Closing database pool...");
await pool.end();
console.log("Database pool closed");
};
process.on("SIGTERM", async () => {
await gracefulPoolShutdown();
process.exit(0);
});
process.on("SIGINT", async () => {
await gracefulPoolShutdown();
process.exit(0);
});
```
This pattern ensures active connections are closed cleanly before your application stops, preventing dropped queries or pool corruption.
## Multi-tenancy
Sevalla fully supports multi-tenancy. You can build multi-tenant Remix applications using [**wildcard domains**](https://docs.sevalla.com/applications/domains), allowing you to efficiently and securely serve multiple tenants from separate subdomains. Use the following best practices for multi-tenancy on Sevalla with your Remix application:
* Use wildcard domains to serve subdomain-based tenants (e.g., `tenant1.app.com`).
* Add custom domains individually for tenants who have their own domains.
* Cache tenant data to reduce database queries and improve performance.
* Validate tenant existence before rendering pages to prevent errors or unauthorized access.
* Isolate tenant data in the database using separate schemas or a `tenant_id` column.
* Leverage free SSL certificates, which are automatically provided for both wildcard and custom domains.
### Remix multi-tenant implementation
**Extract tenant from subdomain in loader:**
```javascript theme={null}
// app/routes/_index.tsx
import type { LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
export async function loader({ request }: LoaderFunctionArgs) {
const url = new URL(request.url);
const hostname = url.hostname;
const subdomain = hostname.split(".")[0];
// Skip for main domain
if (subdomain === "www" || subdomain === "yourdomain") {
return json({ tenant: null });
}
const tenant = await getTenantData(subdomain);
return json({ tenant });
}
export default function Index() {
const { tenant } = useLoaderData();
return (
Welcome to {tenant?.name || "Our Platform"}
);
}
```
**Tenant-specific data:**
```javascript theme={null}
// app/lib/tenant.ts
import { pool } from "./db";
export async function getTenantData(tenantId: string) {
const result = await pool.query(
"SELECT * FROM tenants WHERE subdomain = $1",
[tenantId]
);
return result.rows[0] || null;
}
```
### Custom domains per tenant
Allow tenants to use their own domains (e.g., `customdomain.com` → tenant data).
**Map custom domains to tenants:**
```javascript theme={null}
// app/lib/tenant.ts
export async function getTenantByDomain(hostname: string) {
// First, check if this is a custom domain
const customDomain = await pool.query(
"SELECT tenant_id FROM custom_domains WHERE domain = $1",
[hostname]
);
if (customDomain.rows.length > 0) {
const tenantId = customDomain.rows[0].tenant_id;
return await getTenantById(tenantId);
}
// Otherwise, extract from subdomain
const subdomain = hostname.split(".")[0];
return await getTenantData(subdomain);
}
```
# SvelteKit
Source: https://docs.sevalla.com/quick-starts/javascript/sveltekit
This guide explains how to deploy a basic SvelteKit site to Sevalla.
[SvelteKit](https://svelte.dev/docs/kit/introduction) is a full-stack web framework built on top of Svelte, offering a flexible approach to routing, data loading, and rendering. SvelteKit integrates with Vite for fast development and provides built-in tools for server endpoints, form actions, and progressive enhancement. Its compile-time approach reduces client-side JavaScript, resulting in simple and efficient applications that do not rely heavily on runtime frameworks.
SvelteKit can only be used on Application Hosting; it cannot be deployed as a static site.
We recommend the following best practices to get the best performance when using SvelteKit on Sevalla:
* Use SvelteKit `load` functions for efficient server-side data fetching.
* Add appropriate `Cache-Control` headers to pages and server route responses.
* Enable SvelteKit’s prefetching and preloading to enhance client navigation speed.
* Implement APIs using server routes (`+server.ts`) for better control and performance.
* Ensure compression is enabled in your server configuration.
* Use streaming with async `load` functions to deliver content progressively and reduce TTFB.
## Configuration
To configure your SvelteKit application for Sevalla, you must ensure `@sveltejs/adapter-node` is properly configured in `svelte.config.js` .
The following is an example `svelte.config.js` file for deploying SvelteKit on Sevalla:
```javascript theme={null}
// svelte.config.js
import adapter from "@sveltejs/adapter-node";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter({
out: "build",
precompress: false,
envPrefix: "",
}),
},
};
export default config;
```
## Containerization
### Dockerfile
The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. The following is an example Dockerfile for SvelteKit:
```javascript expandable theme={null}
# Dockerfile for SvelteKit on Sevalla
FROM node:lts-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:lts-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:lts-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3000
ENV HOST=0.0.0.0
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 svelteuser
COPY --from=builder --chown=svelteuser:nodejs /app/build ./build
COPY --from=builder --chown=svelteuser:nodejs /app/package*.json ./
COPY --from=builder --chown=svelteuser:nodejs /app/node_modules ./node_modules
USER svelteuser
EXPOSE 3000
CMD ["node", "build"]
```
### Nixpacks
You can customize the [**Nixpacks**](https://docs.sevalla.com/applications/build-options/nixpacks) build process by defining a `nixpacks.toml` file and using [**Nixpacks-specific environment variables**](https://nixpacks.com/docs/configuration/environment). This allows you to fine-tune how dependencies are installed, how your application is built, and which runtime settings are applied.
The following is an example `nixpacks.toml` configuration:
```javascript theme={null}
[phases.setup]
nixPkgs = ["nodejs", "yarn"]
[phases.install]
cmds = ["yarn install --frozen-lockfile"]
[phases.build]
cmds = ["yarn build"]
[start]
cmd = "node build"
```
Nixpacks will automatically detect your project’s lock file and select the appropriate package manager during deployment.
Additionally, you can specify the [**Node.js version**](https://nixpacks.com/docs/providers/node) used during the build by setting the `NIXPACKS_NODE_VERSION`[**environment variable**](https://nixpacks.com/docs/providers/node#:~:text=Setting%20the%20NIXPACKS_NODE_VERSION%20environment%20variable).
### Buildpacks
If you’re using [**Buildpacks**](https://docs.sevalla.com/applications/build-options/buildpacks), you cannot modify the underlying build phases directly or control dependencies. You must rely on the runtime environment that Buildpacks detects.
Ensure your `package.json` has the correct scripts for the buildpack deployment:
```javascript theme={null}
{
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"start": "node build"
}
}
```
**Required:**
* `build` script: Compiles your SvelteKit application.
* `start` script: Runs the production server (buildpack uses this).
Make sure `@sveltejs/adapter-node` is configured in `svelte.config.js`:
```javascript theme={null}
import adapter from "@sveltejs/adapter-node";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
export default {
preprocess: vitePreprocess(),
kit: {
adapter: adapter({
out: "build",
}),
},
};
```
## CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your SvelteKit application, we recommend the following best practices:
* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications to ensure global, low-latency delivery.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after critical deployments to ensure users receive updated content.
* Rely on SvelteKit's versioned assets in the `.svelte-kit/output/` directory, which are safe to cache indefinitely.
* Store static files in the `static/` directory, allowing the CDN to serve them efficiently.
### Image Optimization
```javascript theme={null}
```
### Static Assets
Place static assets in the `static/` directory:
```
static/
├── images/
├── fonts/
└── favicon.ico
```
SvelteKit automatically serves these with optimal caching headers.[****](https://docs.sevalla.com/quick-starts/javascript/tanstack#image-optimization)
## Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your SvelteKit application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.
* Use SvelteKit's `invalidateAll` or `invalidate` for client-side revalidation.
### `Cache-Control`
With Sevalla’s Cloudflare integration,`Cache-Control`headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your SvelteKit application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
### `Cache-Control` headers for server routes
```javascript theme={null}
// src/routes/api/public-data/+server.ts
import { json } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async () => {
const data = await fetchPublicData();
return json(data, {
headers: {
"Cache-Control": "public, max-age=3600, s-maxage=3600",
},
});
};
```
#### **Page load function caching with headers**
```javascript theme={null}
// src/routes/products/+page.server.ts
import type { PageServerLoad } from "./$types";
export const load: PageServerLoad = async ({ setHeaders }) => {
const products = await fetchProducts();
setHeaders({
"Cache-Control": "public, max-age=60, s-maxage=3600",
});
return { products };
};
```
```javascript theme={null}
{#each data.products as product (product.id)}
{product.name}
{/each}
```
#### **Server routes with caching**
```javascript theme={null}
// src/routes/api/products/+server.ts
import { json } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async () => {
const products = await fetchProducts();
return json(products, {
headers: {
"Cache-Control": "public, s-maxage=3600",
},
});
};
```
#### **Client-side revalidation**
```javascript theme={null}
```
## Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
* Close connections cleanly (e.g., database pools, Redis) to prevent resource leaks.
* Test deployments in staging with monitoring scripts to validate health checks.
### Basic health check
```javascript theme={null}
// src/routes/api/health/+server.ts
import { json } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async () => {
return json(
{ status: "ok", timestamp: new Date().toISOString() },
{ status: 200 }
);
};
```
## Graceful shutdown
SvelteKit with adapter-node provides automatic graceful shutdown, but you can add custom cleanup logic, such as closing database connections, by handling `SIGTERM` and `SIGINT` yourself. The example below demonstrates how to shut down a PostgreSQL connection pool during termination:
```javascript theme={null}
// src/lib/server/db.ts
import { Pool } from "pg";
export const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20,
idleTimeoutMillis: 30000,
});
// Graceful pool shutdown
const gracefulPoolShutdown = async () => {
console.log("Closing database pool...");
await pool.end();
console.log("Database pool closed");
};
process.on("SIGTERM", async () => {
await gracefulPoolShutdown();
process.exit(0);
});
process.on("SIGINT", async () => {
await gracefulPoolShutdown();
process.exit(0);
});
```
## Multi-tenancy
Sevalla fully supports multi-tenancy. You can build multi-tenant SvelteKit applications using [**wildcard domains**](https://docs.sevalla.com/applications/domains), allowing you to efficiently and securely serve multiple tenants from separate subdomains. Use the following best practices for multi-tenancy on Sevalla with your SvelteKit application:
* Use wildcard domains to serve subdomain-based tenants (e.g., `tenant1.app.com`).
* Add custom domains individually for tenants who have their own domains.
* Cache tenant data to reduce database queries and improve performance.
* Validate tenant existence before rendering pages to prevent errors or unauthorized access.
* Isolate tenant data in the database using separate schemas or a `tenant_id` column.
* Leverage free SSL certificates, which are automatically provided for both wildcard and custom domains.
### SvelteKit multi-tenant implementation
**Extract tenant from subdomain in load function:**
```javascript theme={null}
// src/routes/+page.server.ts
import type { PageServerLoad } from "./$types";
export const load: PageServerLoad = async ({ request, url }) => {
const hostname = url.hostname;
const subdomain = hostname.split(".")[0];
// Skip for main domain
if (subdomain === "www" || subdomain === "yourdomain") {
return { tenant: null };
}
const tenant = await getTenantData(subdomain);
return { tenant };
};
```
```javascript theme={null}
Welcome to {data.tenant?.name || "Our Platform"}
```
**Tenant-specific data:**
```javascript theme={null}
// src/lib/server/tenant.ts
import { pool } from "./db";
export async function getTenantData(tenantId: string) {
const result = await pool.query(
"SELECT * FROM tenants WHERE subdomain = $1",
[tenantId]
);
return result.rows[0] || null;
}
```
### **Custom domains per tenant**
Allow tenants to use their own domains (e.g., `customdomain.com` → tenant data).
**Map custom domains to tenants:**
```javascript theme={null}
// src/lib/server/tenant.ts
export async function getTenantByDomain(hostname: string) {
// First, check if this is a custom domain
const customDomain = await pool.query(
"SELECT tenant_id FROM custom_domains WHERE domain = $1",
[hostname]
);
if (customDomain.rows.length > 0) {
const tenantId = customDomain.rows[0].tenant_id;
return await getTenantById(tenantId);
}
// Otherwise, extract from subdomain
const subdomain = hostname.split(".")[0];
return await getTenantData(subdomain);
}
```
# TanStack
Source: https://docs.sevalla.com/quick-starts/javascript/tanstack
This guide explains how to deploy a basic TanStack site to Sevalla.
[TanStack](https://tanstack.com/) is a suite of high-performance, framework-agnostic libraries that solve common challenges in modern web development, including data fetching, routing, tables, forms, and virtualization. Its headless, composable design gives developers full control over rendering while providing powerful utilities for complex UI and data workflows.
TanStack can only be used on Application Hosting; it cannot be deployed as a static site.
We recommend the following best practices to get the best performance when using TanStack on Sevalla:
* Use TanStack Router loaders for efficient server-side data fetching.
* Apply proper `Cache-Control` headers on API responses to maximize CDN performance.
* Utilize TanStack Router’s prefetching to enhance client navigation speed.
* Use server handlers for API endpoints to reduce latency and improve SSR performance.
* Enable Nitro compression in production for smaller payloads.
* Reduce bundle size with code splitting and lazy loading for route-based components.
## Containerization
### Dockerfile
The build for [**Dockerfiles**](https://docs.sevalla.com/applications/build-options/dockerfile) is fully customizable. The following is an example Dockerfile for TanStack:
```javascript expandable theme={null}
# Dockerfile
FROM node:lts-alpine AS base
# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Copy package files
COPY package.json package-lock.json* ./
RUN npm ci
# Build the application
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build with Vite/Nitro
RUN npm run build
# Production image
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nodejs
# Copy built application
COPY --from=builder --chown=nodejs:nodejs /app/.output ./.output
COPY --from=builder /app/package.json ./package.json
USER nodejs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", ".output/server/index.mjs"]
```
### Nixpacks
[Nixpacks](https://docs.sevalla.com/applications/build-options/nixpacks) automatically uses `npm run start` as the default start command, so no configuration is required for most TanStack deployments. If you need more control, you can customize the build process by creating a `nixpacks.toml` file and using [Nixpacks-specific environment variables](https://nixpacks.com/docs/configuration/environment) to adjust dependency installation, build steps, and runtime settings.
When deploying TanStack, you must also set `NIXPACKS_SPA_CADDY=false` to ensure that Nixpacks does not apply single-page-app routing behavior.
## CDN
Sevalla provides a premium, Cloudflare-powered CDN for Application Hosting at no additional cost. To get the most out of Sevalla’s CDN when deploying your TanStack application, we recommend the following best practices:
* [**Enable the CDN**](https://docs.sevalla.com/applications/cdn) for all production applications to ensure global, low-latency delivery.
* Set appropriate `Cache-Control` headers on API routes to ensure proper caching behavior.
* [**Purge CDN cache**](https://docs.sevalla.com/applications/cdn#clear-the-cdn-cache) after critical deployments to ensure users receive updated content.
* Rely on Vite's versioned assets in the `dist/ `directory, which are safe to cache indefinitely.
* Store static files in the `public/` directory, allowing the CDN to serve them efficiently.
* Use Nitro's built-in compression for optimal performance.
### Image optimization
```javascript theme={null}
// src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
component: Home,
})
function Home() {
return (
)
}
```
### Static assets
Place static assets in the `public/` directory, Nitro and Vite automatically serve these with optimal caching headers:
```javascript theme={null}
public/
├── images/
├── fonts/
└── favicon.ico
```
Nitro and Vite automatically serve these with optimal caching headers.
## Edge caching
[**Edge caching**](https://docs.sevalla.com/applications/edge-caching) stores your Sevalla site cache on Cloudflare’s 260+ global data centers, delivering responses from the location nearest to each visitor for faster performance. To maximize the benefits of Sevalla’s Edge Caching for your TanStack application, we recommend the following best practices:
* Set appropriate `Cache-Control` headers in loaders to control caching behavior.
* Combine edge caching with the CDN for a complete caching strategy.
* Use TanStack Router's navigation for client-side revalidation.
### `Cache-Control`
With Sevalla’s Cloudflare integration, `Cache-Control` headers are respected at the edge, giving you precise control over how content is cached and served globally. The following are some common directives you can use in your TanStack application:
* `public, s-maxage=3600` - Caches the response on the CDN for 1 hour, improving performance for frequently accessed content.
* `public, max-age=31536000, immutable` - Ideal for versioned static assets, allowing them to be cached for up to 1 year with no revalidation.
* `private` - Prevents CDN caching and ensures the response is only cached by the end user’s browser, for personalized or sensitive data.
Sevalla does not yet support the `stale-while-revalidate` Cache-Control directive. To prevent unexpected caching behavior, we recommend not using this directive in your API or asset caching settings.
### `Cache-Control` headers for API routes
```javascript theme={null}
// src/routes/api/public-data.ts
import { createFileRoute } from "@tanstack/react-router";
async function fetchPublicData() {
// Your data fetching logic
return { data: "example" };
}
export const Route = createFileRoute("/api/public-data")({
server: {
handlers: {
GET: async () => {
const data = await fetchPublicData();
return new Response(JSON.stringify(data), {
status: 200,
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, max-age=3600, s-maxage=3600",
},
});
},
},
},
});
```
### Loader caching with headers
```javascript theme={null}
// src/routes/products/index.tsx
import { createFileRoute } from '@tanstack/react-router'
async function fetchProducts() {
// Your data fetching logic
return [{ id: 1, name: 'Product 1' }]
}
export const Route = createFileRoute('/products/')({
loader: async () => {
const products = await fetchProducts()
return { products }
},
headers: () => ({
'Cache-Control': 'public, max-age=60, s-maxage=3600',
}),
component: Products,
})
function Products() {
const { products } = Route.useLoaderData()
return (
{products.map((product) => (
{product.name}
))}
)
}
```
### API routes with caching
```javascript theme={null}
// src/routes/api/products.ts
import { createFileRoute } from "@tanstack/react-router";
async function fetchProducts() {
// Your data fetching logic
return [{ id: 1, name: "Product 1" }];
}
export const Route = createFileRoute("/api/products")({
server: {
handlers: {
GET: async () => {
const products = await fetchProducts();
return new Response(JSON.stringify(products), {
status: 200,
headers: {
"Content-Type": "application/json",
"Cache-Control": "public, s-maxage=3600",
},
});
},
},
},
});
```
### Client-side revalidation
```javascript theme={null}
// src/routes/blog/$slug.tsx
import { createFileRoute } from '@tanstack/react-router'
import { useEffect } from 'react'
export const Route = createFileRoute('/blog/$slug')({
component: BlogPost,
})
function BlogPost() {
const navigate = Route.useNavigate()
useEffect(() => {
// Revalidate on focus
const handleFocus = () => {
navigate({ to: '.', replace: true })
}
window.addEventListener("focus", handleFocus)
return () => window.removeEventListener("focus", handleFocus)
}, [navigate])
return {/* ... */}
}
```
## Health checks
Ensure your application remains available during deployments by implementing health checks:
* Always implement [**health checks**](https://docs.sevalla.com/applications/processes#health-checks) for production applications.
* Keep checks lightweight; responses should complete in under 1 second.
* Verify critical dependencies (e.g., databases, Redis) as part of the checks.
* Return 200 for degraded states to allow deployments to continue smoothly.
* Return 503 only for critical failures that require pod restarts.
* Close connections cleanly (e.g., database pools, Redis) to prevent resource leaks.
* Test deployments in staging with monitoring scripts to validate health checks.
### **Basic health check**
```javascript theme={null}
// src/routes/api/health.ts
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/api/health")({
server: {
handlers: {
GET: async () => {
return new Response(
JSON.stringify({ status: "ok", timestamp: new Date().toISOString() }),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
);
},
},
},
});
```
## Graceful shutdown
TanStack Start with Nitro provides automatic graceful shutdown, but you can add custom cleanup logic, such as closing database connections, by handling `SIGTERM` and `SIGINT` yourself. The example below demonstrates how to shut down a PostgreSQL connection pool during termination:
```javascript theme={null}
// src/lib/db.server.ts
import { Pool } from "pg";
export const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20,
idleTimeoutMillis: 30000,
});
// Graceful pool shutdown
const gracefulPoolShutdown = async () => {
console.log("Closing database pool...");
await pool.end();
console.log("Database pool closed");
};
process.on("SIGTERM", async () => {
await gracefulPoolShutdown();
process.exit(0);
});
process.on("SIGINT", async () => {
await gracefulPoolShutdown();
process.exit(0);
});
```
This pattern ensures active connections are closed cleanly before your application stops, preventing dropped queries or pool corruption.
## Multi-tenancy
Sevalla fully supports multi-tenancy. You can build multi-tenant TanStack applications using [**wildcard domains**](https://docs.sevalla.com/applications/domains), allowing you to efficiently and securely serve multiple tenants from separate subdomains. Use the following best practices for multi-tenancy on Sevalla with your TanStack application:
* Use wildcard domains to serve subdomain-based tenants (e.g., `tenant1.app.com`).
* Add custom domains individually for tenants who have their own domains.
* Cache tenant data to reduce database queries and improve performance.
* Validate tenant existence before rendering pages to prevent errors or unauthorized access.
* Isolate tenant data in the database using separate schemas or a `tenant_id` column.
* Leverage free SSL certificates, which are automatically provided for both wildcard and custom domains.
### TanStack start multi-tenant implementation
**Extract tenant from subdomain in loader:**
```javascript theme={null}
// src/routes/index.tsx
import { createFileRoute } from '@tanstack/react-router'
// Tenant data fetching function
async function getTenantData(tenantId: string) {
// Implement database query or API call
// Example: return await db.query("SELECT * FROM tenants WHERE subdomain = $1", [tenantId])
return { id: tenantId, name: `Tenant ${tenantId}` }
}
export const Route = createFileRoute('/')({
loader: async ({ context, location }) => {
const url = new URL(location.href)
const hostname = url.hostname
const subdomain = hostname.split(".")[0]
// Skip for main domain
if (subdomain === "www" || subdomain === "yourdomain") {
return { tenant: null }
}
const tenant = await getTenantData(subdomain)
return { tenant }
},
component: Home,
})
function Home() {
const { tenant } = Route.useLoaderData()
return (
Welcome to {tenant?.name || "Our Platform"}
)
}
```
**Tenant-specific data:**
```javascript theme={null}
// src/lib/tenant.ts
import { pool } from "./db";
export async function getTenantData(tenantId: string) {
const result = await pool.query(
"SELECT * FROM tenants WHERE subdomain = $1",
[tenantId]
);
return result.rows[0] || null;
}
```
### Custom domains per tenant
Allow tenants to use their own domains (e.g., `customdomain.com` → tenant data).
**Map custom domains to tenants:**
```javascript theme={null}
// src/lib/tenant.ts
export async function getTenantByDomain(hostname: string) {
// First, check if this is a custom domain
const customDomain = await pool.query(
"SELECT tenant_id FROM custom_domains WHERE domain = $1",
[hostname]
);
if (customDomain.rows.length > 0) {
const tenantId = customDomain.rows[0].tenant_id;
return await getTenantById(tenantId);
}
// Otherwise, extract from subdomain
const subdomain = hostname.split(".")[0];
return await getTenantData(subdomain);
}
```
# Turborepo
Source: https://docs.sevalla.com/quick-starts/javascript/turborepo
This guide explains how to deploy a service to Sevalla from a monorepo using Turborepo.
[Turborepo](https://turborepo.com/) is a framework-agnostic tool for efficiently managing monorepos. It includes the following features:
* **Turborepo build system** - Intelligent build orchestration with incremental builds.
* **Parallel execution** - Run tasks across multiple packages simultaneously with automatic CPU optimization.
* **Task pipelines** - Define dependencies between tasks to ensure optimal execution order.
* **Workspace management** - Organize multiple packages and apps in a single repository.
* **Incremental adoption** - Add Turborepo to existing monorepos without refactoring.
* **Selective task execution** - Run tasks only for packages affected by your changes.
* **TypeScript support** - Full TypeScript configuration across all workspaces.
* **Framework agnostic** - Works with Next.js, React, Vue, Express, and any JavaScript/TypeScript framework.
## Configuration
In Sevalla, each application instance can host only a single app. Therefore, in Monorepos with workspace dependencies (`packages/*`), your services must be built from the repository root directory to access all workspace packages and ensure all dependencies resolve correctly.\
To do this, all you need to do is ensure that your `build` and `start` commands are specific to the service you wish to deploy. Refer to our examples in the containerization section for guidance on how to achieve this.
### Environment variable types
* `globalEnv`: Variables that apply to every task and invalidate the cache when changed. Use these for settings that impact all builds, such as`NODE_ENV`, `DATABASE_URL`.
* **Task-specific** `env`: Variables scoped to individual tasks only. These help avoid unnecessary cache invalidation by limiting their impact to the tasks that actually use them.
* **Framework variables**: Variables like `NEXT_PUBLIC_*`, `VITE_*`, or `REACT_APP_*` are automatically detected by Turborepo and will invalidate the cache when modified. Use these for client-exposed configuration.
* `passThroughEnv`: Variables that are passed to tasks but do not affect cache keys. Ideal for runtime-only values that should not trigger new builds, such as secrets or tokens that don’t alter the build output.
## Containerization
### Dockerfile
You must create separate Dockerfiles for each application, the web frontend, and the API backend, located in the repository’s root directory. After creating each application in Sevalla, [assign the correct Dockerfile](https://docs.sevalla.com/applications/settings#build-strategy) to the corresponding service within **Applications** > ***application name*** > **Settings** > **Update build strategy**. Inside each Dockerfile, make sure to use the appropriate build and start commands defined in that application's `package.json`.
Example Dockerfile for the web frontend:
```javascript expandable theme={null}
# Dockerfile for Next.js Web App
# Production-ready build for deploying web app separately
FROM node:lts-alpine AS base
# Enable pnpm
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
# Builder stage - install dependencies and build
FROM base AS builder
WORKDIR /app
# Copy root package files
COPY package.json pnpm-lock.yaml* pnpm-workspace.yaml ./
# Copy all package.json files to install workspace dependencies
COPY apps/web/package.json ./apps/web/package.json
COPY apps/api/package.json ./apps/api/package.json
COPY packages/ui/package.json ./packages/ui/package.json
COPY packages/typescript-config/package.json ./packages/typescript-config/package.json
# Install all dependencies (needed for workspace)
RUN pnpm install
# Copy source files
COPY . .
# Build web app and its dependencies using Turborepo
RUN pnpm build:web
# Runner stage - minimal production image
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3000
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy Next.js standalone build
# The standalone output includes all dependencies needed to run
# (No need to copy node_modules - standalone bundles everything)
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
USER nextjs
EXPOSE 3000
# Start Next.js standalone server
CMD ["node", "apps/web/server.js"]
```
Example Dockerfile for the API backend:
```javascript expandable theme={null}
# Dockerfile for Express API
# Production-ready build for deploying API separately
FROM node:lts-alpine AS base
# Enable pnpm
RUN corepack enable && corepack prepare pnpm@9.15.4 --activate
# Builder stage - install dependencies and build
FROM base AS builder
WORKDIR /app
# Copy root package files
COPY package.json pnpm-lock.yaml* pnpm-workspace.yaml ./
# Copy all package.json files to install workspace dependencies
COPY apps/web/package.json ./apps/web/package.json
COPY apps/api/package.json ./apps/api/package.json
COPY packages/ui/package.json ./packages/ui/package.json
COPY packages/typescript-config/package.json ./packages/typescript-config/package.json
# Install all dependencies (needed for workspace)
RUN pnpm install
# Copy source files
COPY . .
# Build API using Turborepo
RUN pnpm build:api
# Runner stage - minimal production image
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3001
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 apiuser
# Copy built API
COPY --from=builder --chown=apiuser:nodejs /app/apps/api/dist ./dist
COPY --from=builder --chown=apiuser:nodejs /app/apps/api/package.json ./package.json
# Copy only production node_modules from builder
# This avoids workspace resolution issues and is more efficient
COPY --from=builder --chown=apiuser:nodejs /app/node_modules ./node_modules
USER apiuser
EXPOSE 3001
# Start Express API
CMD ["node", "dist/index.js"]
```
### Nixpacks
You must create a separate `nixpacks.toml` file for each application, the web frontend, and the API backend, located in the repository’s root directory.
Alternatively, you can use the following Nixpacks environment variables to specify the build and start commands:
* `NIXPACKS_BUILD_CMD`
* `NIXPACKS_START_CMD`
You can control the Node.js version used during the build by using an `.nvmrc` file, the `engines` field in `package.json`, or the `NIXPACKS_NODE_VERSION` environment variable. If none are set, Nixpacks defaults to Node.js 18.
Example `nixpacks.toml` file for the web frontend:
```javascript theme={null}
[phases.build]
cmds = [
"pnpm build:web"
]
[start]
cmd = "pnpm start:web"
```
Example `nixpacks.toml` file for the API backend:
```javascript theme={null}
[phases.build]
cmds = [
"pnpm build:api"
]
[start]
cmd = "pnpm start:api"
```
# Migrate from Heroku to Sevalla
Source: https://docs.sevalla.com/quick-starts/migrate-from-heroku
Learn how to migrate your applications from Heroku to Sevalla with this step-by-step guide.
Sevalla has the best feature parity with Heroku on the market. No other alternative covers as many Heroku features out of the box.
As of February 2026, Heroku has transitioned to maintenance-focused support. With Sevalla, you get the same workflow you're used to (buildpacks, Procfiles, pipelines, preview apps, 12-factor architecture) without having to rethink how you deploy. Bring your existing Git repos, buildpacks, or Docker images and get running without changes.
This guide explains how Heroku concepts map to Sevalla, enabling you to plan your migration with confidence.
If you encounter any issues during the migration, we've got you covered. [Contact our support ](https://docs.sevalla.com/support/contact-support)using the **chat icon** in the lower right corner of Sevalla.
## Why migrate to Sevalla
Beyond Heroku's shift to maintenance mode, Sevalla provides several advantages:
* **Lower costs** - Competitive pricing with no surprise add-on fees. Databases, object storage, CDN, and DDoS protection are integrated into the platform rather than sold as third-party add-ons.
* **Built-in CDN and edge caching** - Powered by Cloudflare's global network spanning 260+ cities in 100+ countries. Enabled with a single click, no add-on required.
* **DDoS protection included** - Enterprise-level Cloudflare DDoS protection on every application at no extra cost.
* **Private networking** - Internal connections between your applications and databases stay within the network, with no exposure to the public internet.
* **Flexible build options** - Choose between Nixpacks (20+ languages), Heroku Buildpacks, or your own Dockerfile.
* **Preview environments** - Automatically generated for pull requests through pipelines, making it easy to test changes before promoting to production.
* **Persistent storage** - Attach disks directly to your application pods, something Heroku doesn't natively support.
* **Modern analytics** - Built-in compute and web analytics with request metrics, country-level breakdowns, response times, and zoomable charts.
## Feature mapping
The tables below show how Heroku features and terminology map to their Sevalla equivalents.
### Compute
| Heroku | Sevalla |
| --------------------------------------------- | --------------------------------------------------------------------- |
| App | [Application](/applications/get-started/add-an-application) |
| Dyno | [Process](/applications/processes) |
| Dyno type (Eco, Basic, Standard, Performance) | Process size (Hobby, S1, S2, etc.) |
| Web dyno | [Web process](/applications/processes#web-process) |
| Worker dyno | [Background worker](/applications/processes#background-worker) |
| Heroku Scheduler / clock process | [Cron job](/applications/processes#cron-job) |
| One-off dyno (`heroku run`) | [Job process](/applications/processes#job) |
| Config vars | [Environment variables](/applications/environment-variables) |
| Dyno scaling (manual) | [Manual scaling](/applications/scalability) (vertical and horizontal) |
| Autoscaling (Performance dynos) | [Automatic horizontal scaling](/applications/scalability) (CPU-based) |
### Deployment
| Heroku | Sevalla |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Git push deploy | [Git deploy](https://docs.sevalla.com/applications/git/overview) (GitHub, GitLab, Bitbucket) |
| Container Registry deploy | [Docker image deploy](/applications/docker-images) (Docker Hub, GHCR, GitLab Registry) |
| Buildpacks | [Buildpacks](/applications/build-options/buildpacks) or [Nixpacks](/applications/build-options/nixpacks) (default) |
| Procfile | [Procfile](/applications/processes) (also supported) |
| Release phase (`release` process) | [Job process](/applications/processes#job) (before/after deployment) |
| Preboot (zero-downtime deploys) | [Health checks](/applications/processes#web-process) (readiness and liveness probes) |
| Review apps | [Preview apps](/applications/get-started/pipelines) (via pipelines) |
| Pipelines (dev → staging → prod) | [Pipelines](/applications/get-started/pipelines) with promote support |
| Deploy hooks (HTTP notification) | [Deploy hooks](/applications/settings) (trigger deploys via POST) |
| Automatic deploys from branch | [Automatic deployment](/applications/deployments) on push |
### Networking
| Heroku | Sevalla |
| ------------------------- | ------------------------------------------------------------------------- |
| Custom domains | [Custom domains](/applications/domains) with free auto-SSL via Cloudflare |
| SSL certificates (ACM) | Automatic free SSL (included with every domain) |
| Private Spaces networking | [Private networking](/applications/networking) (internal connections) |
| - | [CDN](/applications/cdn) (Cloudflare, 260+ cities, free) |
| - | [Edge caching](/applications/edge-caching) |
| - | [IP restrictions](/applications/networking) (allowlist/denylist) |
| - | [TCP proxy](/applications/networking) (expose non-HTTP services) |
### Datastores
| Heroku | Sevalla |
| ------------------------------ | -------------------------------------------------------------------------------- |
| Heroku Postgres | [PostgreSQL](/databases/overview) |
| JawsDB MySQL (add-on) | [MySQL](/databases/overview) |
| - | [MariaDB](/databases/overview) |
| Heroku Key-Value Store (Redis) | [Redis](/databases/overview) |
| - | [Valkey](/databases/overview) |
| - | [Database Studio](/databases/database-studio) (built-in management UI) |
| PG Backups | [Automatic daily backups](/databases/backups) (7-day retention) + manual backups |
### Storage and assets
| Heroku | Sevalla |
| ----------------------- | ------------------------------------------------------------------------------------ |
| Ephemeral filesystem | Ephemeral filesystem (default) |
| - | [Persistent storage](/applications/storage) (10 GB-1 TB attachable disks) |
| S3 add-on (third-party) | [Object storage](/object-storage/overview) (S3-compatible, powered by Cloudflare R2) |
### Observability
| Heroku | Sevalla |
| ---------------- | ----------------------------------------------------------------------------------------------------------- |
| Application logs | [Runtime logs](/applications/runtime-logs) (up to 30 days, filterable) |
| Log drains | Runtime logs with structured data, JSON/CSV export |
| Heroku Metrics | [Analytics](/applications/analytics) (CPU, memory, RPM, response time, status codes, country breakdown) |
| - | [Webhooks](https://docs.sevalla.com/tools/webhooks) (deployment events, app/database/static site lifecycle) |
### Platform
| Heroku | Sevalla |
| ---------------- | ------------------------------------------------------------------------------------------------------------------ |
| Heroku Teams | [Company settings](/company-settings/user-management) with role-based user management |
| Heroku API | [Sevalla API](https://api-docs.sevalla.com/) |
| SSO (Enterprise) | [SSO](https://docs.sevalla.com/company-settings/single-sign-on/overview) (Google, Microsoft, Okta, OneLogin, Ping) |
| - | [Static site hosting](/static-sites/overview) (free) |
| - | [Templates](/templates/overview) (one-click deploy) |
| - | [Hibernation](/applications/scalability) (auto-sleep idle apps, wake on traffic) |
### Enterprise and security
| Heroku | Sevalla |
| -------------------------------- | ------------------------------------------------------------------------------------ |
| SOC 2 Type II | [SOC 2 Type II](/service-information/soc-2) |
| ISO 27001 | ISO 27001 |
| GDPR | GDPR |
| DDoS protection (Private Spaces) | Built-in Cloudflare DDoS protection (all plans) |
| SSO (Enterprise only) | [SSO](https://docs.sevalla.com/company-settings/single-sign-on/overview) (all plans) |
| Team roles | [Role-based access control](/company-settings/user-management) |
| 2FA | [2FA](/user-settings/logging-in) (required for all accounts) |
| 99.9% uptime SLA | [99.9% uptime SLA](/service-information/guaranteed-uptime) |
## Phase 1: Prepare to migrate
Before moving anything, take inventory of your Heroku setup so nothing gets missed.
### Create a Sevalla account
Sign up at [sevalla.com](https://sevalla.com) if you haven't already. You can explore the dashboard and create resources before committing to a migration.
### Catalog your Heroku resources
For each Heroku app, document the following:
1. **Procfile processes** - List every process type and its command. Each one maps to a Sevalla process:
```text theme={null}
web: npm run start
worker: npm run worker
release: npm run migrate
```
* `web` becomes your [web process](/applications/processes#web-process)
* `worker` becomes a [background worker](/applications/processes#background-worker)
* `release` becomes a [job process](/applications/processes#job) with a "Before deployment" start policy
2. **Config vars** - Export all environment variables. You can import these into Sevalla via the dashboard or by uploading a `.env` file.
3. **Add-ons** - Identify your Heroku Postgres, Redis, and any third-party add-ons. Many third-party services (like SendGrid, Mailgun, or Sentry) continue working after migration since they connect via environment variables.
4. **Custom domains** - Note all custom domains and their DNS configuration.
## Phase 2: Recreate your app on Sevalla
### Step 1: Create datastores first
Create your databases before deploying your application so the app can connect immediately on first deploy.
You are not moving data yet. This step creates empty databases for your application to connect to. Data migration happens in Phase 3.
**To create a database:**
1. In the Sevalla dashboard, go to **Databases** > **Create database**.
2. Select the database type and version (PostgreSQL, MySQL, MariaDB, Redis, or Valkey).
3. Configure the database name, user, and password.
4. Select a data center location - this must match the location you choose for your application to enable [internal connections](/applications/networking).
5. Choose a resource size and click **Create database**.
Repeat for each datastore you need to migrate (e.g. one for Postgres, one for Redis).
### Step 2: Create your application
1. In the dashboard, go to **Applications** > **Create** > **Application**.
2. Connect your Git provider (GitHub, GitLab, or Bitbucket) and select your repository, or deploy from a Docker image.
3. Choose the same data center location as your databases.
4. Select a process size.
Don't deploy yet. Configure your environment variables and processes first.
### Step 3: Configure environment variables
1. Go to your application's **Environment variables** tab.
2. Add your Heroku config vars - you can paste key=value pairs in bulk or import a `.env` file.
3. Set each variable's availability to **Runtime**, **Build**, or both.
Sevalla does not automatically set `NODE_ENV` to `production`. Add it manually if your application depends on it.
### Step 4: Set up internal connections
Connect your application to the databases you created in Step 1:
1. Go to your application's **Networking** tab.
2. Under **Connected services**, click **Add internal connection**.
3. Select the database and select **Add environment variables to the application** to auto-populate connection details (e.g. `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_USER`, `DATABASE_PASSWORD`, `DATABASE_NAME`).
4. Click **Add connection**.
Internal connections stay within the Sevalla network and are faster and more secure than external connections.
### Step 5: Set up processes
If your Heroku app uses multiple Procfile processes, add the equivalent processes in Sevalla:
1. Go to your application's **Processes** tab.
2. Update the **web process** start command if needed.
3. Click **Create new process** to add background workers, cron jobs, or jobs as needed.
| Heroku Procfile entry | Sevalla process type |
| -------------------------------- | --------------------------------------- |
| `web: npm run start` | Web process (auto-created) |
| `worker: npm run worker` | Background worker |
| `release: npm run migrate` | Job (start policy: "Before deployment") |
| Clock process / Heroku Scheduler | Cron job (with cron expression) |
### Step 6: Configure build settings
Sevalla defaults to [Nixpacks](/applications/build-options/nixpacks) for builds. If you prefer to keep using Heroku Buildpacks:
1. Go to **Settings** > **Build strategy** > **Update build strategy**.
2. Select **Buildpacks** and choose the appropriate Heroku Pack builder.
You can also switch to a [Dockerfile](/applications/build-options/dockerfile) if your project uses one.
## Phase 3: Migrate data and go live
This phase requires brief downtime for your application. Schedule it during off-peak hours.
### Step 1: Enable maintenance mode on Heroku
Prevent new writes to your Heroku database during migration:
```bash theme={null}
heroku maintenance:on --app YOUR_HEROKU_APP_NAME
```
### Step 2: Export your Heroku database
**PostgreSQL:**
```bash theme={null}
heroku pg:backups:capture --app YOUR_HEROKU_APP_NAME
heroku pg:backups:download --app YOUR_HEROKU_APP_NAME
```
This creates a `latest.dump` file locally.
**Redis:**
Export your Redis data using the method appropriate for your dataset size. For smaller datasets, you can use `redis-cli` with the `--rdb` flag or a tool like `redis-dump`.
### Step 3: Import data into Sevalla
Get your Sevalla database's external connection details from the database's **Networking** tab (enable external connections temporarily if needed).
**PostgreSQL:**
```bash theme={null}
pg_restore --verbose --no-acl --no-owner -d "SEVALLA_EXTERNAL_CONNECTION_STRING" latest.dump
```
**MySQL:**
```bash theme={null}
mysql -h HOSTNAME -u USERNAME -P PORT -p DATABASE_NAME < export.sql
```
For detailed import instructions, see the database-specific guides:
* [PostgreSQL import/export](/databases/import-export/postgresql)
* [MySQL import/export](/databases/import-export/mysql)
* [MariaDB import/export](/databases/import-export/mariadb)
### Alternative: Server-to-server migration without downloading
If downloading the database to a local machine is not an option (e.g. for security or compliance reasons, or the dataset is too large), you can spin up a lightweight Sevalla application that migrates data directly between the two databases. Data flows server-to-server and never touches a local machine.
1. Create a new Sevalla application with a Dockerfile that includes the database client tools you need (e.g. `postgres:17` or `mysql:9` images already have them).
2. Add environment variables for both the Heroku source and the Sevalla target connection strings.
3. Set the start command to pipe the export directly into the import:
**PostgreSQL:**
```bash theme={null}
pg_dump --no-acl --no-owner -d "$SOURCE_DATABASE_URL" | pg_restore --no-acl --no-owner -d "$TARGET_DATABASE_URL"
```
**MySQL:**
```bash theme={null}
mysqldump --no-tablespaces -h $SOURCE_HOST -u $SOURCE_USER -P $SOURCE_PORT -p$SOURCE_PASSWORD $SOURCE_DB | mysql -h $TARGET_HOST -u $TARGET_USER -P $TARGET_PORT -p$TARGET_PASSWORD $TARGET_DB
```
4. Deploy the application and monitor the logs to track progress.
5. Once the migration completes, delete the migration application.
This approach keeps your data in transit between servers only, which is important for large databases and environments with strict data handling policies. Make sure both databases are accessible from the Sevalla application's data center.
### Step 4: Deploy your application
Go to your application's **Deployments** page and click **Deploy now**. Monitor the deployment log to verify everything builds and starts correctly.
### Step 5: Update DNS records
Once your application is running on Sevalla:
1. Go to your application's **Domains** tab and add your custom domain.
2. Add the TXT record for domain verification at your DNS provider.
3. Add the CNAME record for SSL certificate provisioning.
4. Update your A record to point to the IP address provided by Sevalla.
5. Allow time for DNS propagation.
For step-by-step instructions, see [Custom domains](/applications/domains).
### Step 6: Verify and disable Heroku
After confirming your application works correctly on Sevalla:
1. Test all critical functionality.
2. Verify database data integrity.
3. Check that background workers and cron jobs are running as expected.
4. Disable external connections on your Sevalla database if you enabled them for import.
5. Scale down or delete your Heroku resources.
## What's next
Now that your application is running on Sevalla, explore these features:
* [Pipelines](/applications/get-started/pipelines) - Set up dev/staging/production environments with preview apps.
* [CDN and edge caching](/applications/cdn) - Enable the built-in Cloudflare CDN for faster delivery.
* [Analytics](/applications/analytics) - Monitor performance with built-in compute and web analytics.
* [Auto-scaling](/applications/scalability) - Configure automatic horizontal scaling based on CPU usage.
* [Webhooks](https://docs.sevalla.com/tools/webhooks) - Get notified about deployment events and resource lifecycle changes.
If you encounter any issues during the migration, we've got you covered. [Contact our support team](https://docs.sevalla.com/support/contact-support) using the **chat icon** in the lower right corner of Sevalla.
# Python overview
Source: https://docs.sevalla.com/quick-starts/python
Discover more about running Python applications and sites on Sevalla.
[Python](https://www.python.org/) is a versatile, high-level programming language widely used for building web applications and backend services. Its simplicity, readability, and extensive ecosystem of libraries and frameworks make it ideal for app hosting. Popular web frameworks, such as Django, Flask, and FastAPI, provide tools for routing, templating, database management, and API development, enabling developers to build scalable applications efficiently. Python also supports integrations with task queues, caching systems, and cloud services, making it well-suited for deploying modern web apps on Sevalla.
## Framework guides
* [Django](https://docs.sevalla.com/quick-starts/python/django)
* [FastAPI](https://docs.sevalla.com/quick-starts/python/fastapi)
* [Flask](https://docs.sevalla.com/quick-starts/python/flask)
## Best practices
### Use a hosted database
In most cases, SQLite databases are not suitable for production. Instead, you can use a hosted database on Sevalla for your app.
[Create a database](https://docs.sevalla.com/databases/get-started/add-a-database) in Sevalla and select either Postgres, MySQL, or MariaDB.
You can also [add an internal connection](https://docs.sevalla.com/applications/networking#add-a-private-connection) from the application to the database to add the required environment variables.
### Migrations
Migrations must run after your image has been built but before the container is started. We recommend [creating a job](https://docs.sevalla.com/applications/processes#job-process) to run the migrate command before deployment.
### Background tasks
We recommend using Celery and Redis for your background tasks. However, you can use other task queues, such as Huey and RQ.
### Caching
Use Redis caching to help reduce database load, lower latency, and improve scalability for web applications. Within Sevalla, you can [create and connect a Redis database](https://docs.sevalla.com/databases/get-started/add-a-database) to your Python app.
We also recommend using Sevalla’s CDN and edge caching to maximize performance.
### Health checks
To support zero-downtime deployments, we recommend configuring a health check endpoint in your Python application. This allows Sevalla to verify that your app is running correctly before routing traffic to it.
There are multiple ways to implement health checks in Python, depending on the level of control and visibility required.
# Django introduction
Source: https://docs.sevalla.com/quick-starts/python/django
This is an overview of the steps required to deploy a basic Django site to Sevalla.
[Django](https://www.djangoproject.com/) is a high-level Python web framework designed for rapid development and clean, pragmatic design. It follows a “batteries-included” approach, providing built-in tools for authentication, database management, security, and templating. With its emphasis on scalability, maintainability, and security, Django is well-suited for building robust web applications and APIs.
## Application settings and deployment
The [Deployment](https://docs.sevalla.com/quick-starts/python/django/deployment) section walks you through configuring your `settings.py` and `.env` file correctly before deploying your Django application. It also covers creating a database in Sevalla and choosing between Nixpacks or a Dockerfile, with guidance on configuring your application based on the selected deployment method and instructions for deploying the application.
## Object storage
The [Object Storage](https://docs.sevalla.com/quick-starts/python/django/object-storage) section explains how to set up and integrate Sevalla's object storage into your Django application.
## Caching
The [Caching](https://docs.sevalla.com/quick-starts/python/django/caching) page explains how to configure Django’s caching framework using Redis and how to fully leverage Sevalla’s CDN and edge caching to maximize performance.
## Async
[Async](https://docs.sevalla.com/quick-starts/python/django/async) explains how to run your application with an ASGI server to take full advantage of async views in Django.
## Background tasks
The [Background Tasks](https://docs.sevalla.com/quick-starts/python/django/background-tasks) section explains how to add background task workers to your Django app using Celery and Redis.
## Health checks
[Health checks](https://docs.sevalla.com/quick-starts/python/django/health-checks) explains the options available to integrate health check endpoints into your Django app for zero-downtime deployments.
## Multi-Tenancy
[Multi-Tenancy](https://docs.sevalla.com/quick-starts/python/django/multitenancy) guides you through setting up a Django-Tenants-enabled application on Sevalla.
# Django - Async
Source: https://docs.sevalla.com/quick-starts/python/django/async
This page explains how to set up async views for your Django application on Sevalla.
Django supports async views even when running under WSGI servers like Gunicorn, but this setup doesn’t deliver the full performance benefits of asynchronous execution. To take full advantage of async views in Django, your application must be run with an ASGI server.
Instead of Gunicorn, install an ASGI server like Granian and add it to your `requirements.txt` file.
```shellsession theme={null}
pip install granian
pip freeze > requirements.txt
```
Within Sevalla, [update your start command](https://docs.sevalla.com/applications/processes#edit-the-web-process) to a custom one that uses Granian in **Processes** > **Web process** > **Update process**.
```
granian --interface asginl example.asgi:application --host 0.0.0.0 --port 8080
```
The name of your project and the port can be changed to match your app.
# Django - Background tasks
Source: https://docs.sevalla.com/quick-starts/python/django/background-tasks
Find out how to add background tasks to your Django app in Sevalla.
If your main app process has been successfully deployed on Sevalla, adding a background task worker only requires a few additional steps.
For this example, we use Celery and Redis; however, the same approach can be applied to other task queues, such as Huey and RQ.
Add both `celery` and `redis` to your dependencies.
```shellsession theme={null}
pip install celery redis
pip freeze > requirements.txt
```
Then, create a file called `celery.py` in your project directory. The following is the same starter code used by the [Celery documentation](https://docs.celeryq.dev/en/stable/django/first-steps-with-django.html#using-celery-with-django).
```python theme={null}
# celery.py
import os # [!code ++:15]
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings')
app = Celery('example')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()
@app.task(bind=True, ignore_result=True)
def debug_task(self):
print(f'Request: {self.request!r}')
```
The project name needs to be updated from *example* to your project name in both `os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'example.settings')` and `app = Celery('example')`.
In the `__init__.py` file in the same directory, you'll need to import the celery app object.
```python theme={null}
#__init__.py
from .celery import app as celery_app # [!code ++:3]
__all__ = ('celery_app',)
```
In your `settings.py` file, you'll need to add your broker URL to the `CELERY_BROKER_URL` setting. Since Redis is used in this example, you can use the `REDIS_URL` environment variable as the value.
```python theme={null}
CELERY_BROKER_URL = env('REDIS_URL') # [!code ++]
```
Within Sevalla, you can [create a Redis database](https://docs.sevalla.com/databases/get-started/add-a-database) and connect it to your app. Make sure you add the `REDIS_URL` to your app when connecting the Redis service to your app.
To get the Celery worker to start, you can create a new background worker with the following start command:
`celery -A example worker -c 1 -l INFO`
Celery starts by referencing the name of your project. The concurrency is set to one here to avoid overuse of your resources. You can adjust the value to match the needs of your app.
Once you deploy your app, you'll see Celery startup information in your logs.
To test the debug task defined above, you can go to the web terminal and manually trigger the debug task.
In the web terminal, start the virtual environment and run the task from the Django shell.
```shellsession theme={null}
. /opt/venv/bin/activate
python manage.py shell
```
Inside the shell:
```python theme={null}
from example.celery import debug_task
debug_task.delay()
```
The addition of `delay` to the `debug_task` call will send the task to the Celery broker instead of running it directly. Within the runtime logs, you can view the output message.
# Django - Caching
Source: https://docs.sevalla.com/quick-starts/python/django/caching
This article explains how to set up caching for your Django application in Sevalla.
## Cache framework using Redis
Django's cache framework can be used with a Django app deployed on Sevalla by connecting a Redis service to your Django app.
To enable the cache framework, Redis needs to be installed and your settings updated.
### Install
The Python Redis library must be a dependency so that Django can connect to your Redis instance.
```shellsession theme={null}
pip install redis
pip freeze > requirements.txt
```
### Settings
You need to add the caches settings to `settings.py`.
Reference the `RedisCache` backend that is included with Django. Use your preferred method for defining configuration values for `LOCATION`, which is the URL of your Redis instance. django-environ is used for this example.
```python theme={null}
CACHES = { # [!code ++:6]
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": env('REDIS_URL'),
}
}
```
Within Sevalla, you can [create and connect a Redis database](https://docs.sevalla.com/databases/get-started/add-a-database) to your Django app. After creating the Redis instance, go to **Networking** and then click **Add internal connection**, select the Redis instance you created, and then add the `REDIS_URL` environment variable to the application.
### Example
To use the cache on a view, you can import the `cache_page` function and decorate some of your view functions or classes. Here is an example:
1. Create an app that allows you to add a new view.
```shellsession theme={null}
python manage.py startapp app
```
2. Create a view function and decorate it with `cache_page`. This example will cache the view for two minutes.
```python theme={null}
# app/views.py
from django.http import HttpResponse # [!code ++:7]
from django.utils import timezone
from django.views.decorators.cache import cache_page
@cache_page(60 * 2)
def cached_view(request):
return HttpResponse(f"Cached at {timezone.now()} for two minutes")
```
```python theme={null}
# example/urls.py
from django.contrib import admin
from django.urls import path
from app.views import cached_view # [!code ++]
urlpatterns = [
path('admin/', admin.site.urls),
path('cached/', cached_view, name='cached_view'), # [!code ++]
]
```
3. Navigate to the `cached/` endpoint, the time the view was added to the cache will be displayed until the cache is updated.
The settings for `RedisCache` used here will also work with template fragment caching and direct use of the cache API.
If you want to cache your entire site, consider using edge caching instead.
## CDN
If you are using WhiteNoise to serve your static files, you can [enable the CDN setting](https://docs.sevalla.com/applications/cdn#enable-or-disable-sevalla’s-cdn) to cache your static assets on Cloudflare.
To verify your static files are being cached correctly, request a file and inspect the response headers. The `cf-cache-status` header should be either `HIT` or `MISS`. `MISS` should only occur when the file needs to be set or updated in the CDN. `HIT` will be the expected value for most requests.
## Edge Caching
If your application primarily serves pages that don’t change frequently, you can use [edge caching](https://docs.sevalla.com/applications/edge-caching#enable-or-disable-edge-caching) to store and serve pre-rendered responses. This caching applies across the entire application, and only endpoints that explicitly disable caching via response headers will be excluded, resulting in faster load times and reduced server load.
You can prevent caching by decorating a view with `never_cache`.
```python theme={null}
from django.views.decorators.cache import never_cache
@never_cache
def login(request):
...
```
By default, all admin views in Django use the `never_cache` decorator.
To control how long a page will remain in the cache, you need to set the `max-age` response headers. One way to do that is to use the `cache_control` decorator.
```python theme={null}
from django.views.decorators.cache import cache_control
@cache_control(max_age=60*60*24)
def page(request):
...
```
To verify your pages are being cached correctly, request a page and inspect the response headers. The `cf-cache-status` header should be either `HIT` or `MISS`. `MISS` should only occur when the page needs to be set or updated in the CDN. `HIT` will be the expected value for most requests.
# Django - Deployment
Source: https://docs.sevalla.com/quick-starts/python/django/deployment
Find out how to configure and deploy your Django application.
## Application settings
Before you can deploy your app, you need to update your `settings.py` file so your app can run properly in both development and production environments.
If you don't already have a preferred approach to handle your settings, you can use [django-environ](https://django-environ.readthedocs.io/en/latest/). You can install django-environ with your package manager.
```shellsession theme={null}
pip install django-environ
```
django-environ reads values from `.env` in your project's base directory. At a minimum, `.env` needs to include the following variables:
* DEBUG
* SECRET\_KEY
* ALLOWED\_HOSTS
* CSRF\_TRUSTED\_ORIGINS
* DATABASE\_URL
These are the environment variables that typically vary between development and production. You can also add any other project-specific environment variables. This `.env` will only contain your development values.
```shellscript theme={null}
# .env
DEBUG=True # [!code ++:5]
ALLOWED_HOSTS=localhost,127.0.0.1
SECRET_KEY=
CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://127.0.0.1:8000
DATABASE_URL=sqlite:///db.sqlite3
```
After you've created the `.env` file, you need to update your `settings.py` file so django-environ can read `.env` and set the appropriate settings. `DEBUG` should default to `False`, so your production environment never starts in debug mode.
```python theme={null}
# settings.py
import os # [!code ++]
import environ # [!code ++]
from pathlib import Path
env = environ.Env(DEBUG=(bool, False)) # [!code ++]
BASE_DIR = Path(__file__).resolve().parent.parent
environ.Env.read_env(os.path.join(BASE_DIR, '.env')) # [!code ++]
```
For each setting, you can use the env object to retrieve the value. For values that accept a list, `env.list` will convert comma-separated values to a Python list. If those values don't exist, you should default to an empty list, so you have no allowed hosts or CSRF trusted origins.
```python theme={null}
SECRET_KEY = env('SECRET_KEY') # [!code ++]
DEBUG = env('DEBUG') # [!code ++]
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[]) # [!code ++]
CSRF_TRUSTED_ORIGINS = env.list('CSRF_TRUSTED_ORIGINS', default=[]) # [!code ++]
```
For the database, use `env.db()` on the default database; this loads the `DATABASE_URL` value defined in your environment variables.
```python theme={null}
# settings.py
DATABASES = {
'default': { # [!code --:4]
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
'default': env.db(), # [!code ++]
}
```
## Add a hosted database
The filesystem used for your app will be recreated on each deploy, so an SQLite database isn't suitable for production. Instead, you can use a hosted database on Sevalla for your app.
[Create a database](https://docs.sevalla.com/databases/get-started/add-a-database) in Sevalla and select either Postgres, MySQL, or MariaDB.
You also need to install a database driver if you haven't already done so. For example, with Postgres, you can use `psycopg2-binary`.
```shellsession theme={null}
pip install psycopg2-binary
```
## Application server and static files
Django’s built-in development server is not intended for production use, so you should run your application with Gunicorn instead. Because the development server also handles static files by default, you’ll need to use WhiteNoise to serve static assets in production. Both Gunicorn and WhiteNoise must be installed via your package manager as part of your deployment setup.
```shellsession theme={null}
pip install gunicorn whitenoise
```
To use WhiteNoise, you only need to add its middleware in `settings.py`. This middleware should be placed after the `SecurityMiddleware`.
```python theme={null}
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # [!code ++]
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
```
For static files to work properly, you need to define the `STATIC_ROOT` variable in `settings.py`.
```python theme={null}
STATIC_ROOT = BASE_DIR / 'staticfiles' # [!code ++]
```
## Nixpacks
By default, Sevalla builds your application using Nixpacks. Nixpacks can detect that you have a Python app, but you need to specify any extra commands needed to build your app. You also need a start command to tell Nixpacks how to start your app. You can define both commands in a `nixpacks.toml` file in your base directory.
For the build command, you need to run `collectstatic`. For the start command, you need to run both the `migrate` and `gunicorn` command. After the `gunicorn` command, specify the name of your Django project followed by `.wsgi`. The `$PORT` variable can be used to start your app on the port defined in your Sevalla application.
```toml theme={null}
[phases.build] # [!code ++:2]
cmds = ["python manage.py collectstatic --noinput"]
[start] # [!code ++:2]
cmd = "python manage.py migrate && gunicorn example.wsgi -b 0.0.0.0:$PORT"
```
Finally, generate a `requirements.txt` file so your dependencies install during deployment.
```shellsession theme={null}
pip freeze > requirements.txt
```
## Dockerfile
To build your application from a Dockerfile, you need a Dockerfile that ends with your application being started by Gunicorn or any other WSGI server.
The following is a sample Dockerfile that sets up a Python environment, installs your dependencies, collects static files, and then starts a Gunicorn server.
```docker theme={null}
FROM python:latest
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN mkdir /app
WORKDIR /app
RUN pip install --upgrade pip
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
ARG SECRET_KEY
ARG DATABASE_URL
RUN python3 manage.py collectstatic --no-input
CMD ["gunicorn", "example.wsgi"]
```
Django management commands can't run without a secret key and database set, so the `ARG` directive is used to make the associated environment variables available to the build process. These environment variables should be set as available at both buildtime and runtime before deploying your app for the first time.
The command to start with Gunicorn needs to reference the name of your project's WSGI file.
The rest of the Dockerfile can be customized according to your project's specific needs.
### Migrations
Migrations need to happen outside the Dockerfile because there won't be a reference to your actual database in the Dockerfile. Additionally, your migrations must run after your image has been built but before the container is started.
You can [create a job](https://docs.sevalla.com/applications/processes#job-process) to run the migrate command before the container is started. To do this, after you add your application, go to **Processes** > **Create job** > **Job**. For the start command, add `python manage.py migrate`. The start policy should be **before deployment**, and the smallest instance size should be sufficient for migrations.
### Build settings
By default, Sevalla builds applications using Nixpacks, so the [build strategy](https://docs.sevalla.com/applications/settings#build-strategy) must be updated before your Dockerfile can be used.
To update the build strategy, after you add your application, go to **Settings** > **Update build strategy** and change the build strategy from **Nixpacks** to **Dockerfile**.
## Deploy on Sevalla
To deploy your app to [Sevalla using Git](https://docs.sevalla.com/applications/git/overview), your code must be hosted in a Git repository. Sevalla supports any public Git repository or private repositories from GitHub, Bitbucket, and GitLab. You'll need to connect your repo host account with Sevalla if you are using a private repo.
Your repo should have a `.gitignore` that ignores SQLite files, `.env` files, virtual environments, `__pycache__/`, any other files that either have sensitive information or don't need to be tracked in git.
Here is an example .gitignore file:
```text theme={null}
__pycache__/
.env
.venv/
env/
venv/
*.sqlite3
```
You can now [add your application](https://docs.sevalla.com/applications/get-started/add-an-application) in Sevalla and choose the branch and repository for your project. Ensure that you set the location for your application to match the location of your database, allowing them to communicate over an internal network. If your app requires more resources than the defaults of 0.3 GB RAM and 0.3 CPU, then switch to a larger instance size.
After adding the application, you can set up the [environment variables](https://docs.sevalla.com/applications/environment-variables) required for your app. First, go to **Domains** to copy your app’s generated domain. Then go to **Environment variables** to set up the same environment variables defined in `.env` except for `DATABASE_URL`. The values for the variables should be appropriate for production.
* `ALLOWED_HOSTS`: include only the domain with no scheme or trailing slash. (e.g. deploydjangosevalla-4q4g3.sevalla.app).
* `CSRF_TRUSTED_ORGINS`: include the scheme but no trailing slash. (e.g. [https://deploydjangosevalla-4q4g3.sevalla.app](https://deploydjangosevalla-4q4g3.sevalla.app)).
* `DEBUG`: should always be false except for intentional testing.
* `SECRET_KEY`: should be a random string of at least 50 characters.
For the `DATABASE_URL`, go to **Networking** and click **Add internal connection**. Select the database you created earlier, and then select **Add environment variables to the application**. Rename `DB_URL` to `DATABASE_URL` and click **Add internal connection**.
# Django - Health checks
Source: https://docs.sevalla.com/quick-starts/python/django/health-checks
Discover how to integrate health checks into your Django app in Sevalla.
To support zero-downtime deployments, configure a health check endpoint in your Django application. This endpoint allows Sevalla to verify that your app is running correctly before routing traffic to it.
There are multiple ways to implement a health check in Django, depending on the level of control and visibility required.
## Option 1: Use an existing view
If you don’t want to create a new endpoint, you can reuse an existing public view as the health check. The chosen path should return a successful response only when critical dependencies, such as the database or other required services, are functioning correctly. If a failure occurs, the view should return an error status.
## Option 2: Create a dedicated health check view
For more control and clarity, you can create a simple, dedicated health check endpoint. This view can explicitly verify core dependencies, such as database connectivity, by calling `connection.ensure_connection()`. If a connection cannot be established, an exception is raised, and the endpoint returns an error response, indicating the application is unhealthy.
```python theme={null}
# views.py
from django.db import connection
from django.http import HttpResponse
def health_check(request):
connection.ensure_connection()
return HttpResponse("OK", status=200)
```
```python theme={null}
# urls.py
urlpatterns = [
path('health_check/', views.health_check, name='health_check'),
]
```
This view can then be extended with any other checks that your app needs to perform to assess its health.
## Option 3: Use a health check library
You can also use established libraries that provide ready-made health check endpoints. These libraries can automatically verify the health of multiple components, such as databases, caches, task queues, and email services. One example is [**Django Health Check**](https://github.com/revsys/django-health-check), which offers modular checks and configurable endpoints, making it a good choice for more complex applications with multiple dependencies.
# Django - Multi-tenancy
Source: https://docs.sevalla.com/quick-starts/python/django/multitenancy
Discover how to set up your Django app for multi-tenancy in Sevalla.
You can enable multi-tenancy in your Django application using the Django-Tenants library, which allows each tenant to have its own subdomain and database schema, keeping data fully isolated.
The following instructions guide you through setting up a Django-Tenants-enabled application on Sevalla. This example assumes you already have a deployed Django app. It is recommended to start with an empty database, as Django-Tenants applies migrations in a tenant-specific manner.
Additionally, a custom domain is required for this setup, since each tenant will use a separate subdomain to implement the multi-tenancy structure.
## Installation and settings
1. Install the django-tenants library and add it to your dependencies.
```shellsession theme={null}
pip install django-tenants
pip freeze > requirements.txt
```
2. Update the database engine to use the Django-Tenants Postgres backend.
```python theme={null}
# settings.py
DATABASES = {
'default': env.db(engine="django_tenants.postgresql_backend"), # [!code ++]
}
```
3. A custom database router can then be added to `settings.py`.
```python theme={null}
# settings.py
DATABASE_ROUTERS = ( # [!code ++:3]
'django_tenants.routers.TenantSyncRouter',
)
```
4. Add the `TenantMainMiddleware` to the `MIDDLEWARE` list. It should be added after `CommonMiddleware` to avoid any errors.
```python theme={null}
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django_tenants.middleware.main.TenantMainMiddleware', # [!code ++]
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
```
## App and model
In this example, you’ll create two Django apps. The first, `app`, will contain the models used to manage tenants and domains, along with any views that are publicly accessible. The second app, `dashboard`, will be tenant-specific and will contain functionality and views intended only for individual tenants.
```shellsession theme={null}
python manage.py startapp app
python manage.py startapp dashboard
```
The Client and Domain models must be created in `app/models.py`. The Client model is used to create all tenants. The Domain model is used to associate subdomains with the tenants you create.
```python theme={null}
# app/models.py
from django_tenants.models import TenantMixin, DomainMixin # [!code ++:10]
class Client(TenantMixin):
name = models.CharField(max_length=100)
created_on = models.DateField(auto_now_add=True)
auto_create_schema = True
class Domain(DomainMixin):
pass
```
## Other settings
Because some apps should be available globally across the project, while others should be isolated per tenant, you’ll need to adjust how `INSTALLED_APPS` is defined.
Start by defining a `SHARED_APPS` list, which replaces the traditional `INSTALLED_APPS` and includes apps that are shared across all tenants. Next, create a `TENANT_APPS` list containing only the apps that should be available to individual tenants. Finally, define `INSTALLED_APPS` as a combination of both lists.
The `SHARED_APPS` list should also include the `django_tenants` app and the main `app` application that manages tenants and domains.
```python theme={null}
SHARED_APPS = [ # [!code ++]
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_tenants', # [!code ++: 2]
'app',
]
TENANT_APPS = ["dashboard"] # [!code ++]
INSTALLED_APPS = SHARED_APPS + [app for app in TENANT_APPS if app not in SHARED_APPS] # [!code ++]
```
In `settings.py`, configure Django-Tenants, so that it knows where your core tenant and domain models are defined.
```python theme={null}
TENANT_MODEL = "app.Client" # [!code ++:3]
TENANT_DOMAIN_MODEL = "app.Domain"
```
Finally, in `settings.py`, replace the original `ROOT_URLCONF` with a new configuration pointing to `urls_tenants`, which you’ll create shortly. Then, define `PUBLIC_SCHEMA_URLCONF` to point to your original `urls.py` file, which will continue to handle all public (non-tenant) views.
```python theme={null}
ROOT_URLCONF = 'example.urls_tenants' # [!code ++:2]
PUBLIC_SCHEMA_URLCONF = 'example.urls'
```
## Views
Below are two simple example views that illustrate the difference between public views and tenant-specific views.
### **Public View**
This view lives in the shared `app` application and is accessible across the entire project, regardless of tenant.
```python theme={null}
# app/views.py
from django.http import HttpResponse # [!code ++:4]
def index(request):
return HttpResponse("Hello, this is the public-specific view!")
```
### **Tenant-Specific View**
This view belongs to the `dashboard` application and is only available within a tenant context. It uses `request.tenant` to access tenant-specific data.
```python theme={null}
# dashboard/views.py
from django.http import HttpResponse # [!code ++:4]
def index(request):
return HttpResponse(f"Hello, {request.tenant.name}. This is the tenant-specific view!")
```
### **Tenant URL Configuration**
Next, create a `urls_tenants.py` file to define routes that should only be accessible to tenants. This file references views from the tenant-only `dashboard` app.
```python theme={null}
# example/urls_tenants.py
from django.urls import path # [!code ++:7]
from dashboard import views
urlpatterns = [
path('', views.index, name='index'),
]
```
### **Public URL Configuration**
Finally, keep your public routes in the existing `urls.py` file. These URLs are served from the public schema and remain accessible without a tenant context.
```python theme={null}
# example/urls.py
from django.contrib import admin
from django.urls import path
from app import views # [!code ++]
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.index, name='index'), # [!code ++]
]
```
## Deploying to Sevalla
Before deploying your application, create migrations to create the new models in the database.
```shellsession theme={null}
python manage.py makemigrations
```
[Add a custom start command](https://docs.sevalla.com/applications/processes#edit-the-web-process) to prevent the default migrations from running.
```shellsession theme={null}
gunicorn example.wsgi
```
[Create a job process](https://docs.sevalla.com/applications/processes#add-a-job-process) that runs before deployment that uses the `migrate_schemas` command from Django-Tenants.
```shellsession theme={null}
python manage.py migrate_schemas --shared
```
[Add a custom domain](https://docs.sevalla.com/applications/domains#add-domain) to your project so the subdomains work with django-tenants.
You can now deploy your app in **Deployments** > **Deploy now**.
## Create a Tenant
Once your app is deployed and you can see the public view on your page, add a tenant to the system. The tenant can be added through the [web terminal](https://docs.sevalla.com/applications/web-terminal).
Use the bash web terminal, turn on the virtual environment, and then start a Django shell session.
```shellsession theme={null}
. /opt/venv/bin/activate
python manage.py shell
```
Finally, create tenant and domain objects. Ensure the domain you use here matches the domain associated with your app.
```shellsession theme={null}
tenant = Client.objects.create(schema_name='tenant1', name='Tenant One')
Domain.objects.create(domain='tenant1.your-domain.com', tenant=tenant, is_primary=True)
```
Now you should be able to visit both your base domain and the tenant subdomain and see the public and tenant pages. You can also check your database and see that multiple schemas exist.
# Django - Object storage
Source: https://docs.sevalla.com/quick-starts/python/django/object-storage
The guide explains how to set up object storage for your Django application.
If your application supports user-uploaded files (such as media uploads), you’ll need a storage solution separate from the application’s local filesystem. [Sevalla’s object storage](https://docs.sevalla.com/object-storage/overview) is ideal for securely storing and serving these files. Static files can also be delivered from object storage if desired, though this is optional and depends on your application’s setup and performance needs.
## Media Files
Start by [creating an object storage](https://docs.sevalla.com/object-storage/add-an-object-storage) on Sevalla. **Settings** contains all the values needed for your storages settings.
### Install
Before your media files can be uploaded to object storage, the `django-storages` library must be added to your dependencies. Sevalla's object storage is S3-compatible, so the s3 extra should be included when installing, which installs boto3 for you.
```shellsession theme={null}
pip install django-storages[s3]
pip freeze > requirements.txt
```
### Settings
You need to add the storages settings to `settings.py`. Both the signature version of `s3v4` and the `storages.backends.s3.S3Storage` are necessary for Django to properly use the object storage.
You can use your preferred method for defining configuration values for `access_key`, `secret_key`, `bucket_name`, and `endpoint_url`. django-environ is used for this example.
```python theme={null}
STORAGES = { # [!code ++:12]
"default": {
"BACKEND": "storages.backends.s3.S3Storage",
"OPTIONS": {
"access_key": env("MEDIA_BUCKET_ACCESS_KEY"),
"secret_key": env("MEDIA_BUCKET_SECRET_KEY"),
"bucket_name": env("MEDIA_BUCKET_NAME"),
"endpoint_url": env("MEDIA_BUCKET_ENDPOINT_URL"),
"signature_version": "s3v4"
}
}
}
```
If you would like your media bucket to be publicly accessible, in the object storage **Settings**, click **Enable public access**.
Then you'll need to add the `custom_domain` to your storages settings dictionary.
```python theme={null}
STORAGES = { #
"default": {
"BACKEND": "storages.backends.s3.S3Storage",
"OPTIONS": {
"access_key": env("MEDIA_BUCKET_ACCESS_KEY"),
"secret_key": env("MEDIA_BUCKET_SECRET_KEY"),
"bucket_name": env("MEDIA_BUCKET_NAME"),
"endpoint_url": env("MEDIA_BUCKET_ENDPOINT_URL"),
"custom_domain": env("MEDIA_BUCKET_DOMAIN"), # [!code ++]
"signature_version": "s3v4"
}
}
}
```
Once your app is restarted with the configuration values loaded, it will place any user-uploaded files into object storage instead of the file system.
## Static Files
Static files can also be placed in an object storage instead of being served directly from your app with WhiteNoise. If you will have both media files and static files served from an object store, you should use a separate object storage for each type.
Start by [creating a new object storage](https://docs.sevalla.com/object-storage/add-an-object-storage) on Sevalla. To fully support all the static files used for the admin dashboard, you should make your static file object store public.
### Settings
Add separate settings for `staticfiles` in the `STORAGES` dictionary.
```python theme={null}
STORAGES = {
"default": {
"BACKEND": "storages.backends.s3.S3Storage",
"OPTIONS": {
"access_key": env("MEDIA_BUCKET_ACCESS_KEY"),
"secret_key": env("MEDIA_BUCKET_SECRET_KEY"),
"bucket_name": env("MEDIA_BUCKET_NAME"),
"endpoint_url": env("MEDIA_BUCKET_ENDPOINT_URL"),
"signature_version": "s3v4"
}
},
"staticfiles": { # [!code ++:11]
"BACKEND": "storages.backends.s3.S3Storage",
"OPTIONS": {
"access_key": env("STATIC_BUCKET_ACCESS_KEY"),
"secret_key": env("STATIC_BUCKET_SECRET_KEY"),
"bucket_name": env("STATIC_BUCKET_NAME"),
"endpoint_url": env("STATIC_BUCKET_ENDPOINT_URL"),
"custom_domain": env("STATIC_BUCKET_DOMAIN"),
"signature_version": "s3v4"
}
}
}
```
Django doesn't use the `STATIC_URL` setting when `STORAGES` is set but still requires it, so for clarity, you may want to add the proper `STATIC_URL` to `settings.py` .
```python theme={null}
STATIC_URL = 'static/' # [!code --]
STATIC_URL = f'{env("STATIC_BUCKET_DOMAIN")}/' # [!code ++]
```
You can then remove WhiteNoise, if you have it.
```python theme={null}
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # [!code --]
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
```
Your static files will now be uploaded to the bucket when the collectstatic command is run.
The collectstatic command will take longer to run because the static files need to be uploaded to the object storage.
# FastAPI introduction
Source: https://docs.sevalla.com/quick-starts/python/fastapi
This is an overview of the steps required to deploy a basic FastAPI site to Sevalla.
[FastAPI](https://fastapi.tiangolo.com/) is a modern, high-performance web framework for building APIs with Python. It is designed for speed, ease of use, and automatic validation, leveraging Python type hints to generate interactive API documentation and ensure data correctness. FastAPI supports asynchronous programming, making it ideal for handling high-concurrency applications, while integrating easily with databases, authentication systems, and other web technologies.
## Application settings and deployment
The [Deployment](https://docs.sevalla.com/quick-starts/python/fastapi/deployment) section guides you through an example FastAPI app using SQLModel. It includes how to configure the database models, `pydantic-settings` and `main.py`. It also covers creating a database in Sevalla and choosing between Nixpacks or a Dockerfile, with guidance on configuring your application based on the selected deployment method and instructions for deploying the application.
## Object storage
The [Object Storage](https://docs.sevalla.com/quick-starts/python/fastapi/object-storage) section explains how to set up and integrate Sevalla's object storage into your FastAPI application.
## Background tasks
The [Background Tasks](https://docs.sevalla.com/quick-starts/python/fastapi/background-tasks) section explains how to add background task workers to your FastAPI app using Celery and Redis.
## Caching
The [Caching](https://docs.sevalla.com/quick-starts/python/fastapi/caching) page explains how to configure the FastAPI-Cache library using Redis and how to fully leverage Sevalla’s CDN and edge caching to maximize performance.
## Health checks
[Health checks](https://docs.sevalla.com/quick-starts/python/fastapi/health-checks) explains the options available to integrate health check endpoints into your FastAPI app for zero-downtime deployments.
# FastAPI - Background tasks
Source: https://docs.sevalla.com/quick-starts/python/fastapi/background-tasks
Find out how to add background tasks to your FastAPI app in Sevalla.
The built-in FastAPI background tasks functionality will work with Sevalla, but it is designed primarily for lightweight tasks, as it runs in the same process as your app. If you need to handle background tasks outside of your app, you can create a worker to manage these tasks for you.
If your main app process has been successfully deployed on Sevalla, adding a background task worker only requires a few additional steps.
For this example, we use Celery and Redis; however, the same approach can be applied to other task queues, such as Huey and RQ.
Add both `celery` and `redis` to your dependencies.
```shellsession theme={null}
pip install celery redis
pip freeze > requirements.txt
```
Create a new file called `app/worker.py`. This file holds the Celery object and tasks. The following `debug_task` is an example that demonstrates Celery is working properly.
```python theme={null}
# app/worker.py
from celery import Celery
from app.core.config import settings
celery = Celery(__name__)
celery.config_from_object(settings, namespace='CELERY')
@celery.task(bind=True)
def debug_task(self):
print(f'Request: {self.request!r}')
```
Celery loads its configuration from the app’s settings object, so you’ll need to update the settings model in `config.py`. Since Redis will serve as the task broker, set the broker configuration value to `REDIS_URL`.
```python theme={null}
# app/core/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env",)
SQLALCHEMY_DATABASE_URI: str = ""
REDIS_URL: str = "" # [!code ++:5]
@property
def CELERY_BROKER_URL(self) -> str:
return self.REDIS_URL
settings = Settings()
```
If you want to run Celery in your local environment, add the following to your `.env`.
```shellsession theme={null}
# .env
REDIS_URL=redis://localhost:6379/0
```
## Deploy on Sevalla
Within Sevalla, [create a Redis database](https://docs.sevalla.com/databases/get-started/add-a-database) and connect it to your app. Make sure you add the `REDIS_URL` value to your environment variables.
To start the Celery worker, [create a new background worker](https://docs.sevalla.com/applications/processes#add-a-background-worker-process) with the following start command:
`celery -A app.worker worker -c 1 -l INFO`
Celery is started by referencing the name of the entry point file. The concurrency is set to one here to avoid overuse of your resources. You can adjust the value to match the needs of your app.
Once you deploy your app, you'll see Celery startup information in your logs.
To test the debug task defined above, you can go to the [web terminal](https://docs.sevalla.com/applications/web-terminal) and manually trigger the debug task.
Inside the web terminal, start the virtual environment and run the task from the Python REPL.
```shellsession theme={null}
. /opt/venv/bin/activate
python
```
Inside the shell, run the following:
```python theme={null}
from app.worker import debug_task
debug_task.delay()
```
The addition of `delay` to the `debug_task` call will send the task to the Celery broker instead of running it directly. Within the runtime logs, you can view the output message.
# FastAPI - Caching
Source: https://docs.sevalla.com/quick-starts/python/fastapi/caching
This article explains how to set up caching for your FastAPI application in Sevalla.
## FastAPI-Cache using Redis
You can use the FastAPI-Cache library with a FastAPI app deployed on Sevalla by connecting a Redis service to your application.
### Install
To use the caching extension, both FastAPI-Cache and Redis need to be installed.
```shellsession theme={null}
pip install fastapi-cache2 redis
pip freeze > requirements.txt
```
### Code
The library must first be set up as a lifespan function to work with FastAPI. This setup can be added in `main.py`.
```python theme={null}
# app/main.py
from collections.abc import AsyncIterator # [!code ++:5]
from contextlib import asynccontextmanager
from fastapi_cache import FastAPICache
from fastapi_cache.backends.redis import RedisBackend
from redis import asyncio as aioredis
from fastapi import FastAPI
from app.core.config import settings
@asynccontextmanager # [!code ++:5]
async def lifespan(_: FastAPI) -> AsyncIterator[None]:
redis = aioredis.from_url(settings.REDIS_URL)
FastAPICache.init(RedisBackend(redis), prefix="fastapi-cache")
yield
app = FastAPI() # [!code --]
app = FastAPI(lifespan=lifespan) # [!code ++]
```
You then need to add `REDIS_URL` to `config.py`.
```python theme={null}
# app/core/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env",)
SQLALCHEMY_DATABASE_URI: str = ""
REDIS_URL: str = "" # [!code ++]
settings = Settings()
```
If you want to use caching in your local environment, then add `REDIS_URL` to your `.env` file.
```shellsession theme={null}
# .env
SQLALCHEMY_DATABASE_URI=sqlite:///db.sqlite3
REDIS_URL=redis://localhost:6379/0
```
Within Sevalla, you can [create a Redis database](https://docs.sevalla.com/databases/get-started/add-a-database) and connect it to your app. Make sure you add the `REDIS_URL` to your app when you connect the Redis service to it.
### Example
To cache a route, decorate the route with `@cache` decorator. This example caches the route for two minutes.
```python theme={null}
# app/main.py
...
from fastapi import FastAPI # [!code --]
from fastapi import FastAPI, Response # [!code ++]
from app.core.config import settings
from fastapi_cache.decorator import cache # [!code ++:2]
from datetime import datetime
...
app = FastAPI(lifespan=lifespan)
@app.get("/cached") # [!code ++:4]
@cache(expire=120)
def index(response: Response):
return {"message": f"Last generated at {datetime.now()}"}
```
Navigate to the `cached/` endpoint, the time the view was added to the cache will be displayed until the cache is updated.
FastAPI-Cache can also be used with the same configuration to cache regular functions in your app.
If you want to cache your entire API, consider using edge caching instead.
## CDN
Even though static files aren't typically served from FastAPI, if you happen to serve static files, you can take advantage of CDN caching. To add CDN caching, [enable the CDN setting](https://docs.sevalla.com/applications/cdn#enable-or-disable-sevalla’s-cdn) to cache your static assets on Cloudflare.
To verify your static files are being cached correctly, request a file and inspect the response headers. The `cf-cache-status` header should be either `HIT` or `MISS`. `MISS` should only occur when the file needs to be set or updated in the CDN. `HIT` will be the expected value for most requests.
## Edge caching
If your app primarily serves endpoints with data that doesn’t change frequently, you can use [edge caching](https://docs.sevalla.com/applications/edge-caching#enable-or-disable-edge-caching) to cache the responses. This will apply to your entire app, except for endpoints that explicitly include headers preventing caching, which the edge cache will ignore.
You can prevent caching by updating the endpoint's response to have a `Cache-Control` header with the value `no-store`.
```python theme={null}
# main.py
from fastapi import FastAPI, Response
from app.core.config import settings
from datetime import datetime
app = FastAPI()
@app.get("/")
def index(response: Response):
response.headers["Cache-Control"] = "no-store"
return {"message": f"The current time is {datetime.now()}"}
```
To control how long a page will remain in the cache, you need to set the `max-age` value in your `Cache-Control` header.
```python theme={null}
# main.py
from fastapi import FastAPI, Response
from app.core.config import settings
from datetime import datetime
app = FastAPI()
@app.get("/")
def index(response: Response):
response.headers["Cache-Control"] = "no-store"
return {"message": f"The current time is {datetime.now()}"}
@app.get("/page") # [!code ++:4]
def page(response: Response):
response.headers["Cache-Control"] = "max-age=120"
return {"message": f"The current time is {datetime.now()}"}
```
To verify your endpoints are being cached correctly, request an endpoint and inspect the response headers. The `cf-cache-status` header should be either `HIT` or `MISS`. `MISS` should only occur when the page needs to be set or updated in the CDN. `HIT` will be the expected value for most requests.
# FastAPI - Deployment
Source: https://docs.sevalla.com/quick-starts/python/fastapi/deployment
Find out how to configure and deploy your FastAPI application.
## Example app
FastAPI apps can be structured in many ways. For demonstration purposes, this example provides a simple, deployable FastAPI app on Sevalla. The concepts shown here can be applied to any FastAPI application.
What’s included in the example app:
### Database models
This app uses SQLModel as its ORM. All database models should inherit from the `SQLModel` class, which is imported in `models.py`. This ensures consistency and smooth integration with the app’s database layer.
```python theme={null}
# app/models.py
from sqlmodel import SQLModel
```
SQLModel needs a connection to your database, which requires creating an engine. The database URL is provided via the `SQLALCHEMY_DATABASE_URI` setting, which will be defined in `config.py` later.
```python theme={null}
# app/core/db.py
from sqlmodel import create_engine
from app.core.config import settings
engine = create_engine(str(settings.SQLALCHEMY_DATABASE_URI))
```
You need to create a session and a session dependency so your routes can create, read, and modify SQLModel objects.
```python theme={null}
# app/api/deps.py
from fastapi import Depends
from sqlmodel import Session
from typing import Annotated
from app.core.db import engine
def get_session():
with Session(engine) as session:
yield session
SessionDep = Annotated[Session, Depends(get_session)]
```
Alembic is used for database migrations.
The `alembic` directory and its files were generated by the `alembic init app/alembic` command. Inside that directory, the `app/alembic/env.py` and `app/alembic/script.py.mako` files need to be updated to work with your app.
For `alembic.env.py`, the `SQLModel` class needs to be imported from `models.py`, and the database URL needs to be referenced when migrations are run.
```python theme={null}
# app/alembic.env.py
...
target_metadata = None # [!code --]
from app.models import SQLModel # [!code ++:3]
from app.core.config import settings
target_metadata = SQLModel.metadata
...
def get_url(): # [!code ++:2]
return str(settings.SQLALCHEMY_DATABASE_URI)
...
def run_migrations_offline() -> None:
url = config.get_main_option("sqlalchemy.url") # [!code --]
url = get_url() # [!code ++]
...
def run_migrations_online() -> None:
configuration = config.get_section(config.config_ini_section) # [!code ++]
configuration["sqlalchemy.url"] = get_url() # [!code ++]
connectable = engine_from_config(
config.get_section(config.config_ini_section, {}), # [!code --]
configuration, # [!code ++]
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
```
Update `app/alembic/script.py.mako` to include an import for `sqlmodel`.
```python theme={null}
# app/alembic/script.py.mako
from alembic import op
import sqlalchemy as sa
import sqlmodel # [!code ++]
```
### App settings
The `pydantic-settings` package manages all configuration values for the app. If a `.env` file is present, its values will be loaded automatically. Otherwise, the app will fall back to the environment variables defined on the system.
The only required setting for this example is `SQLALCHEMY_DATABASE_URI`, which specifies the connection string used to connect to your database.
```python theme={null}
# app/core/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env")
SQLALCHEMY_DATABASE_URI: str = ""
settings = Settings()
```
In a development environment, you can create a `.env` file to store configuration values that will be loaded when the app starts. When deploying to Sevalla, these [environment variables](https://docs.sevalla.com/applications/environment-variables) can be configured directly through Sevalla instead.
```shellsession theme={null}
# .env
SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://:@:/
```
### Main file
The app’s entry point is `main.py`, where you need to instantiate the FastAPI app object.
```python theme={null}
# app/main.py
from fastapi import FastAPI
from app.core.config import settings
app = FastAPI()
```
### Requirements
The following installs all the requirements for this example app:
```shellsession theme={null}
pip install fastapi[all] sqlmodel
pip install alembic psycopg2-binary
pip freeze > requirements.txt
```
## Add a hosted database
The filesystem used for your app will be recreated on each deploy, so an SQLite database isn't suitable for production. Instead, you can use a hosted database on Sevalla for your app.
[Create a database](https://docs.sevalla.com/databases/get-started/add-a-database) in Sevalla and select either Postgres, MySQL, or MariaDB.
You also need to install a database driver if you haven't already done so. For example, with Postgres, you can use `psycopg2-binary`.
```shellsession theme={null}
pip install psycopg2-binary
```
## Nixpacks
By default, Sevalla uses Nixpacks to build your application.
After you add the application, you need to add custom commands that will both start your app and run migrations before every deploy.
To [update the start command](https://docs.sevalla.com/applications/processes#edit-the-web-process), go to **Processes** > **Web process** > **Update process** and add `fastapi run app/main.py` as your custom start command.
For migrations, you can [create a job](https://docs.sevalla.com/applications/processes#job-process) to run the migrate command before the container is started. To do this, after you add your application, go to **Processes** > **Create job** > **Job**. For the start command, add `alembic upgrade head`. The start policy should be **before deployment**, and the smallest instance size should be sufficient for migrations.
## Dockerfile
To build your application using a Dockerfile, ensure it ends with your FastAPI app being started by the app server.
Below is a sample Dockerfile that sets up a Python environment, installs dependencies, and launches the server.
```docker theme={null}
FROM python:latest
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN mkdir /app
WORKDIR /app
RUN pip install --upgrade pip
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["fastapi", "run", "app/main.py"]
```
The command to start FastAPI must reference the name of the file containing your FastAPI app object.
The rest of the Dockerfile can be customized according to your project's specific needs.
### Migrations
For migrations, you can [create a job](https://docs.sevalla.com/applications/processes#job-process) to run the migrate command before the container is started. To do this, after you add your application, go to **Processes** > **Create job** > **Job**. For the start command, add `alembic upgrade head`. The start policy should be **before deployment**, and the smallest instance size should be sufficient for migrations.
### Build settings
By default, Sevalla builds applications using Nixpacks, so the [build strategy](https://docs.sevalla.com/applications/settings#build-strategy) must be updated before your Dockerfile can be used.
To update the build strategy, after you add your application, go to **Settings** > **Update build strategy** and change the build strategy from **Nixpacks** to **Dockerfile**.
## Deploy on Sevalla
To deploy your app to [Sevalla using Git](https://docs.sevalla.com/applications/git/overview), your code must be hosted in a Git repository. Sevalla supports any public Git repository or private repositories from GitHub, Bitbucket, and GitLab. You'll need to connect your repo host account with Sevalla if you are using a private repo.
Your repo should have a `.gitignore` that ignores SQLite files, `.env` files, virtual environments, `__pycache__/`, any other files that either have sensitive information or don't need to be tracked in git.
Here is an example .gitignore file:
```text theme={null}
__pycache__/
.env
.venv/
env/
venv/
*.sqlite3
```
You can now [add your application](https://docs.sevalla.com/applications/get-started/add-an-application) in Sevalla and choose the branch and repository for your project. Ensure that you set the location for your application to match the location of your database, allowing them to communicate over an internal network. If your app requires more resources than the defaults of 0.3 GB RAM and 0.3 CPU, then switch to a larger instance size.
After adding your application, you can configure the environment variables it requires. For this example, only `SQLALCHEMY_DATABASE_URI` is needed.
Since this variable holds your database URL, go to **Networking** and click **Add internal connection**. Select the database you created earlier, and then select **Add environment variables to the application**. Rename `DB_URL` to `SQLALCHEMY_DATABASE_URI` and click **Add internal connection**.
If you are using PostgreSQL, make sure the connection string starts with `postgresql://` (not `postgres://`) so SQLModel can connect properly.
# FastAPI - Health checks
Source: https://docs.sevalla.com/quick-starts/python/fastapi/health-checks
Discover how to integrate health checks into your FastAPI app in Sevalla.
To support zero-downtime deployments, configure a health check endpoint in your FastAPI application. This endpoint allows Sevalla to verify that your app is running correctly before routing traffic to it.
There are multiple ways to implement a health check in FastAPI, depending on the level of control and visibility required.
## Option 1: Use an existing endpoint
If you prefer not to create a separate health check path, you can use any existing public endpoint in your app. Choose a path that will return an error if a critical service, like your database, is not functioning correctly.
## Option 2: Use a dedicated health check endpoint
A dedicated health check endpoint allows you to explicitly verify the health of your app’s dependencies. For example, you can check database connectivity by executing a simple query such as `session.exec(text("SELECT 1"))`. If the connection fails, the endpoint will return an error.
```python theme={null}
# app/main.py
from fastapi import FastAPI
from app.core.config import settings
from app.api.deps import SessionDep
from sqlalchemy import text
app = FastAPI()
@app.get("/health_check")
def health_check(session: SessionDep):
session.exec(text("SELECT 1"))
return "OK"
```
You can extend this endpoint to include additional checks for other services your app depends on.
## Option 3: Use a health check library
Health check libraries provide ready-made solutions for monitoring the state of your app’s dependencies, such as databases, task queues, caches, and email services. One popular library for FastAPI is [**FastAPI Health**](https://pypi.org/project/fastapi-health/), which simplifies the creation of robust health check endpoints.
# FastAPI - Object Storage
Source: https://docs.sevalla.com/quick-starts/python/fastapi/object-storage
The guide explains how to set up object storage for your FastAPI application.
If your application supports user-uploaded files (such as media uploads), you’ll need a storage solution separate from the application’s local filesystem. [Sevalla’s object storage](https://docs.sevalla.com/object-storage/overview) is ideal for securely storing and serving these files.
## Configuration
Start by [creating an object storage](https://docs.sevalla.com/object-storage/add-an-object-storage) on Sevalla. **Settings** contains all the values needed for your storages settings.
This example requires the following [environment variables](https://docs.sevalla.com/applications/environment-variables):
* `BUCKET_ENDPOINT`
* `BUCKET_SECRET_KEY`
* `BUCKET_ACCESS_KEY`
* `BUCKET_NAME`
The values for these environment variables can be found on the Sevalla object store **Settings** page.
In the FastAPI project, the settings can be added to `config.py`.
```python theme={null}
# app/core/config.py
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env",)
SQLALCHEMY_DATABASE_URI: str = ""
BUCKET_ENDPOINT: str = "" # [!code ++:4]
BUCKET_ACCESS_KEY: str = ""
BUCKET_SECRET_KEY: str = ""
BUCKET_NAME: str = ""
```
## Install
To upload files from FastAPI, install `boto3`. Sevalla's object storage is S3-compatible, allowing the S3 client in boto3 to be used for interfacing with the object store on Sevalla.
```shellsession theme={null}
pip install boto3
pip freeze > requirements.txt
```
## Example
### Create a client with a dependency function
Before you can upload or read files in your bucket, you need to create an S3 client. This client is used for all S3-related methods. For this example, a function is added to `dependencies.py` and used inside any route that requires the `boto3` client.
```python theme={null}
# app/core/dependencies.py
import boto3 # [!code ++:12]
from botocore.client import Config
from app.core.config import settings
def get_s3_client():
return boto3.client(
"s3",
endpoint_url=settings.BUCKET_ENDPOINT,
aws_access_key_id=settings.BUCKET_ACCESS_KEY,
aws_secret_access_key=settings.BUCKET_SECRET_KEY,
config=Config(signature_version='s3v4')
)
```
### Upload a file
One method you can use to upload files is to take a file object (with a `.read() method`) and pass it to the `upload_fileobj` method. This adds it to the provided bucket with the supplied filename. This file object can come from using the `UploadFile` type.
```python theme={null}
# app/main.py
from fastapi import FastAPI, Depends, UploadFile # [!code ++]
from app.core.config import settings
from app.core.dependencies import get_s3_client # [!code ++]
app = FastAPI()
@app.post("/") # [!code ++:8]
def upload(file: UploadFile, s3_client=Depends(get_s3_client)):
s3_client.upload_fileobj(
file.file,
settings.BUCKET_NAME,
file.filename
)
return {"filename": file.filename}
```
### List files
The `list_objects_v2` method returns all the files in the supplied bucket.
If your bucket is private, pre-signed URLs can be created to grant access to a file for a limited period.
```python theme={null}
# app/main.py
...
@app.get("/") # [!code ++:11]
def files(s3_client=Depends(get_s3_client)):
files = []
response = s3_client.list_objects_v2(Bucket=settings.BUCKET_NAME)
for item in response.get('Contents', []):
files.append({"filename": item['Key'], "url": s3_client.generate_presigned_url(
'get_object',
Params={'Bucket': settings.BUCKET_NAME, 'Key': item['Key']},
ExpiresIn=60,
)})
return {"files": files}
```
# Flask introduction
Source: https://docs.sevalla.com/quick-starts/python/flask
This is an overview of the steps required to deploy a basic Flask site to Sevalla.
[Flask](https://flask.palletsprojects.com/) is a lightweight and flexible Python web framework designed for building web applications quickly and easily. It provides the essentials for routing, request handling, and templating without enforcing a specific project structure, making it highly extensible with third-party libraries. Flask is ideal for both small projects and large applications, providing developers with full control over components such as databases, authentication, and caching, while keeping the core simple and minimal.
## Application settings and deployment
The [Deployment](https://docs.sevalla.com/quick-starts/python/flask/deployment) section guides you through an example Flask app using SQLAlchemy. It includes how to configure the database models, extensions, application factory, run file, and app settings. It also covers creating a database in Sevalla and choosing between Nixpacks or a Dockerfile, with guidance on configuring your application based on the selected deployment method and instructions for deploying the application.
## Background tasks
The [Background Tasks](https://docs.sevalla.com/quick-starts/python/flask/background-tasks) section explains how to add background task workers to your Flask app using Celery and Redis.
## Caching
The [Caching](https://docs.sevalla.com/quick-starts/python/flask/caching) page explains how to configure Flask-Caching using Redis and how to fully leverage Sevalla’s CDN and edge caching to maximize performance.
## Health checks
[Health checks](https://docs.sevalla.com/quick-starts/python/flask/health-checks) explains the options available to integrate health check endpoints into your Flask app for zero-downtime deployments.
# Flask - Background tasks
Source: https://docs.sevalla.com/quick-starts/python/flask/background-tasks
Find out how to add background tasks to your Flask app in Sevalla.
If your main app process has been successfully deployed on Sevalla, adding a background task worker only requires a few additional steps.
For this example, we use Celery and Redis; however, the same approach can be applied to other task queues, such as Huey and RQ.
Add both `celery` and `redis` to your dependencies.
```shellsession theme={null}
pip install celery redis
pip freeze > requirements.txt
```
In the `extensions.py` file, add a `celery_init_app` function. The following is the same starter code used by the [Flask documentation](https://flask.palletsprojects.com/en/stable/patterns/celery/).
```python theme={null}
# app/extensions.py
from flask import Flask # [!code ++:2]
from celery import Celery, Task
from flask_alembic import Alembic
from flask_sqlalchemy_lite import SQLAlchemy
from .models import Base
db = SQLAlchemy()
alembic = Alembic(metadatas=Base.metadata)
def celery_init_app(app: Flask) -> Celery: # [!code ++:12]
class FlaskTask(Task):
def __call__(self, *args: object, **kwargs: object) -> object:
with app.app_context():
return self.run(*args, **kwargs)
celery_app = Celery(app.name, task_cls=FlaskTask)
celery_app.config_from_object(app.config["CELERY"])
celery_app.set_default()
app.extensions["celery"] = celery_app
return celery_app
```
Create a simple task in a `tasks.py` file to verify Celery is working properly.
```python theme={null}
# app/tasks.py
from celery import shared_task
@shared_task(bind=True, ignore_result=True)
def debug_task(self):
print(f'Request: {self.request!r}')
```
In `__init__.py`, pass the Flask app instance to this new function so it can be properly initialized. You’ll also need to import the `debug_task` function to ensure Celery discovers it at startup. In a real-world application, this explicit import is usually unnecessary, as tasks are typically imported indirectly through your route or module imports.
```python theme={null}
# app/__init__.py
from flask import Flask
from .extensions import db, alembic, celery_init_app # [!code ++]
from .tasks import debug_task # [!code ++]
def create_app():
app = Flask(__name__)
app.config.from_prefixed_env()
db.init_app(app)
alembic.init_app(app)
celery_init_app(app) # [!code ++]
return app
```
At the same level as `run.py`, create a file named `make_celery.py` to serve as the entry point for your Celery worker. This file is responsible for initializing Celery with your application’s configuration. The `load_dotenv` function is used to load values from the `.env` file into the environment when Celery starts, which is only necessary for local development. Environment variables are provided automatically when running on Sevalla.
```python theme={null}
# make_celery.py
from app import create_app
from dotenv import load_dotenv
load_dotenv()
flask_app = create_app()
celery_app = flask_app.extensions["celery"]
```
If you want to run Celery in your local environment, add the following to your `.env`.
```shellsession theme={null}
# .env
FLASK_CELERY__broker_url=redis://localhost:6379/0
FLASK_CELERY__result_backend=redis://localhost:6379/0
```
## Deploy on Sevalla
Within Sevalla, [create a Redis database](https://docs.sevalla.com/databases/get-started/add-a-database) and connect it to your app. Make sure you change the `REDIS_URL` environment variable to `FLASK_CELERY__broker_url` when adding the environment variables from your Redis instance. If you also want to use Redis to store your Celery results, add the value `FLASK_CELERY__result_backend`.
To start the Celery worker, [create a new background worker](https://docs.sevalla.com/applications/processes#add-a-background-worker-process) with the following start command:
`celery -A make_celery worker -c 1 -l INFO`
Celery is started by referencing the name of the entry point file. The concurrency is set to one here to avoid overuse of your resources. You can adjust the value to match the needs of your app.
Once you deploy your app, you'll see Celery startup information in your logs.
To test the debug task defined above, you can go to the [web terminal](https://docs.sevalla.com/applications/web-terminal) and manually trigger the debug task.
Inside the web terminal, start the virtual environment and run the task from the Flask shell.
```shellsession theme={null}
. /opt/venv/bin/activate
flask shell
```
Inside the shell, run the following:
```python theme={null}
from app.tasks import debug_task
debug_task.delay()
```
The addition of `delay` to the `debug_task` call sends the task to the Celery broker instead of running it directly. Within the runtime logs, you can view the output message.
# Flask - Caching
Source: https://docs.sevalla.com/quick-starts/python/flask/caching
This article explains how to set up caching for your Flask application in Sevalla.
## Flask-Caching with Redis
You can use the Flask-Caching extension with a Flask app deployed on Sevalla by connecting a Redis service to your application.
### Install
To use the caching extension, both Flask-Caching and Redis need to be installed.
```shellsession theme={null}
pip install flask-caching redis
pip freeze > requirements.txt
```
### Code
The extension needs to be instantiated inside of `extensions.py`.
```python theme={null}
# extensions.py
from flask_alembic import Alembic
from flask_sqlalchemy_lite import SQLAlchemy
from flask_caching import Cache # [!code ++]
from .models import Base
db = SQLAlchemy()
alembic = Alembic(metadatas=Base.metadata)
cache = Cache() # [!code ++]
```
And initialized in `__init__.py`.
```python theme={null}
# init.py
from flask import Flask
from .extensions import db, alembic, cache # [!code ++]
def create_app():
app = Flask(__name__)
app.config.from_prefixed_env()
db.init_app(app)
alembic.init_app(app)
cache.init_app(app) # [!code ++]
return app
```
If you want to use caching in your local environment, add the `FLASK_CACHE_TYPE` and `FLASK_CACHE_REDIS_URL` values to your `.env` file.
```shellsession theme={null}
# .env
FLASK_CACHE_TYPE=RedisCache
FLASK_CACHE_REDIS_URL=redis://localhost:6379/0
```
Within Sevalla, you can [create a Redis database](https://docs.sevalla.com/databases/get-started/add-a-database) and connect it to your app. Make sure you change the `REDIS_URL` environment variable to `FLASK_CACHE_REDIS_URL` and add it to the application.
You also need to add the environment variable `FLASK_CACHE_TYPE` with the value `RedisCache`.
### Example
To cache a route, use the `cache` object to decorate the route with `@cache.cached()`. This example caches the route for two minutes.
```python theme={null}
# app/__init__.py
from datetime import datetime
from flask import Flask
from .extensions import db, alembic, cache
def create_app():
app = Flask(__name__)
app.config.from_prefixed_env()
db.init_app(app)
alembic.init_app(app)
cache.init_app(app)
@app.route("/cached") # [!code ++:4]
@cache.cached(timeout=60 * 2)
def cached_view():
return f"Cached at {datetime.now()} for two minutes"
return app
```
Navigate to the `cached/` endpoint, the time the view was added to the cache will be displayed until the cache is updated.
Flask-Caching can also be used with the same configuration to cache both templates and regular functions in your app.
If you want to cache your entire site, consider using edge caching instead.
## CDN
Since static files are served by the Flask app when using `url_for('static')`, you can [enable the CDN setting](https://docs.sevalla.com/applications/cdn#enable-or-disable-sevalla%E2%80%99s-cdn) to cache your static assets on Cloudflare.
To verify your static files are being cached correctly, request a file and inspect the response headers. The `cf-cache-status` header should be either `HIT` or `MISS`. `MISS` should only occur when the file needs to be set or updated in the CDN. `HIT` will be the expected value for most requests.
## Edge Caching
If your app primarily serves endpoints with data that doesn’t change frequently, you can use [edge caching](https://docs.sevalla.com/applications/edge-caching#enable-or-disable-edge-caching) to cache the responses. This will apply to your entire app, except for endpoints that explicitly include headers preventing caching, which the edge cache will ignore.
You can prevent caching by updating the route's response to have `response.cache_control.no_store = True`
```python theme={null}
from datetime import datetime # [!code ++]
from flask import Flask, make_response # [!code ++]
from .extensions import db, alembic
def create_app():
app = Flask(__name__)
app.config.from_prefixed_env()
db.init_app(app)
alembic.init_app(app)
@app.route("/") # [!code ++:5]
def index():
response = make_response(f"Last generated at {datetime.now()}")
response.cache_control.no_store = True
return response
return app
```
To control how long a page will remain in the cache, you need to set the `response.cache_control.max_age` value.
```python theme={null}
from datetime import datetime
from flask import Flask, make_response
from .extensions import db, alembic
def create_app():
app = Flask(__name__)
app.config.from_prefixed_env()
db.init_app(app)
alembic.init_app(app)
@app.route("/")
def index():
response = make_response(f"Last generated at {datetime.now()}")
response.cache_control.no_store = True
return response
@app.route("/page") # [!code ++:5]
def page():
response = make_response(f"Cached at {datetime.now()} for two minutes")
response.cache_control.max_age = 60*2
return response
return app
```
Instead of configuring caching directly within individual routes, you can apply caching more globally by using the `after_request` decorator or by creating a custom decorator. This approach helps keep your route handlers clean and makes it easier to apply consistent caching behavior across multiple endpoints.
To verify your pages are being cached correctly, request a page and inspect the response headers. The `cf-cache-status` header should be either `HIT` or `MISS`. `MISS` should only occur when the page needs to be set or updated in the CDN. `HIT` will be the expected value for most requests.
# Flask - Deployment
Source: https://docs.sevalla.com/quick-starts/python/flask/deployment
Find out how to configure and deploy your Flask application.
## Example app
There are many ways to structure a Flask application, so this guide uses a simple example to demonstrate how to deploy a Flask app on Sevalla. The same approach can be adapted to fit most Flask project layouts and use cases.
What’s included in the example app:
### Database models
This Flask app uses SQLAlchemy for its ORM. Only the Base model is necessary. Any other models for the app inherit from the Base class.
```python theme={null}
#app/models.py
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
```
### Extensions
This example only requires two extensions:
* [Flask-SQLAlchemy-Lite](https://flask-sqlalchemy-lite.readthedocs.io/): A lightweight extension that integrates SQLAlchemy with Flask, allowing you to configure and manage your database connection using your Flask app’s existing configuration.
* [Flask-Alembic](https://flask-alembic.readthedocs.io/): Provides database migration support for Flask applications, enabling you to generate and apply schema migrations based on your SQLAlchemy models.
```python theme={null}
# app/extensions.py
from flask_alembic import Alembic
from flask_sqlalchemy_lite import SQLAlchemy
from .models import Base
db = SQLAlchemy()
alembic = Alembic(metadatas=Base.metadata)
```
### Application factory
In `__init__.py`, the `create_app` function instantiates the Flask app object, loads config values from environment variables, and initializes both extensions on the Flask app.
```python theme={null}
# app/__init__.py
from flask import Flask
from .extensions import db, alembic
def create_app():
app = Flask(__name__)
app.config.from_prefixed_env()
db.init_app(app)
alembic.init_app(app)
return app
```
### Run file
The Flask development server can automatically discover and run the `create_app` application factory, but production servers like Gunicorn cannot. To address this, you need to add a separate `run.py` file that explicitly calls `create_app` and exposes the application instance for the production server to run.
```python theme={null}
# run.py
from app import create_app
app = create_app()
```
### App settings file
For this project, all configuration values are read from environment variables prefixed with `FLASK_`. During development, you can use a `.env` file to define these values so they’re automatically loaded when the app starts. When deploying to Sevalla, these [environment variables](https://docs.sevalla.com/applications/environment-variables) can be configured directly through Sevalla instead.
This application requires a single configuration value that defines the database connection URL.
```shellsession theme={null}
# .env
FLASK_SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://:@:/
```
### Requirements
The following installs all the requirements for this example app:
```shellsession theme={null}
pip install flask python-dotenv
pip install flask-sqlalchemy-lite flask-alembic
pip install gunicorn psycopg2-binary
pip freeze > requirements.txt
```
## Add a hosted database
The filesystem used for your app will be recreated on each deploy, so an SQLite database isn't suitable for production. Instead, you can use a hosted database on Sevalla for your app.
[Create a database](https://docs.sevalla.com/databases/get-started/add-a-database) in Sevalla and select either Postgres, MySQL, or MariaDB.
You also need to install a database driver if you haven't already done so. For example, with Postgres, you can use `psycopg2-binary`.
```shellsession theme={null}
pip install psycopg2-binary
```
## Nixpacks
By default, Sevalla uses Nixpacks to build your application.
After you add the application, you need to add custom commands that will both start your app and run migrations before every deploy.
To [update the start command](https://docs.sevalla.com/applications/processes#edit-the-web-process), go to **Processes** > **Web process** > **Update process** and add `gunicorn run:app` as your custom start command.
For migrations, you can [create a job](https://docs.sevalla.com/applications/processes#job-process) to run the migrate command before the container is started. To do this, after you add your application, go to **Processes** > **Create job** > **Job**. For the start command, add `flask db upgrade`. The start policy should be **before deployment**, and the smallest instance size should be sufficient for migrations.
## Dockerfile
To build your application from a Dockerfile, you need a Dockerfile that ends with your application being started by Gunicorn or any other WSGI server.
The following is a sample Dockerfile that sets up a Python environment, installs your dependencies, and then starts a Gunicorn server.
```docker theme={null}
FROM python:latest
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
RUN mkdir /app
WORKDIR /app
RUN pip install --upgrade pip
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "run:app"]
```
The command to start Gunicorn must reference the name of the file containing your Flask app object.
The rest of the Dockerfile can be customized according to your project's specific needs.
### Migrations
For migrations, you can [create a job](https://docs.sevalla.com/applications/processes#job-process) to run the migrate command before the container is started. To do this, after you add your application, go to **Processes** > **Create job** > **Job**. For the start command, add `flask db upgrade`. The start policy should be **before deployment**, and the smallest instance size should be sufficient for migrations.
### Build settings
By default, Sevalla builds applications using Nixpacks, so the [build strategy](https://docs.sevalla.com/applications/settings#build-strategy) must be updated before your Dockerfile can be used.
To update the build strategy, after you add your application, go to **Settings** > **Update build strategy** and change the build strategy from **Nixpacks** to **Dockerfile**.
## Deploy on Sevalla
To deploy your app to [Sevalla using Git](https://docs.sevalla.com/applications/git/overview), your code must be hosted in a Git repository. Sevalla supports any public Git repository or private repositories from GitHub, Bitbucket, and GitLab. You'll need to connect your repo host account with Sevalla if you are using a private repo.
Your repo should have a `.gitignore` that ignores SQLite files, `.env` files, virtual environments, `__pycache__/`, any other files that either have sensitive information or don't need to be tracked in git.
Here is an example .gitignore file:
```text theme={null}
__pycache__/
.env
.venv/
env/
venv/
*.sqlite3
```
You can now [add your application](https://docs.sevalla.com/applications/get-started/add-an-application) in Sevalla and choose the branch and repository for your project. Ensure that you set the location for your application to match the location of your database, allowing them to communicate over an internal network. If your app requires more resources than the defaults of 0.3 GB RAM and 0.3 CPU, then switch to a larger instance size.
After adding your application, you can configure the environment variables it requires. For this example, only `FLASK_SQLALCHEMY_ENGINES__default` is needed.
Since this variable holds your database URL, go to **Networking** and click **Add internal connection**. Select the database you created earlier, and then select **Add environment variables to the application**. Rename `DB_URL` to `FLASK_SQLALCHEMY_ENGINES__default` and click **Add internal connection**.
If you are using PostgreSQL, make sure the connection string starts with `postgresql://` (not `postgres://`) so SQLAlchemy can connect properly.
# Flask - Health checks
Source: https://docs.sevalla.com/quick-starts/python/flask/health-checks
Discover how to integrate health checks into your Flask app in Sevalla.
To support zero-downtime deployments, configure a health check endpoint in your Flask application. This endpoint allows Sevalla to verify that your app is running correctly before routing traffic to it.
There are multiple ways to implement a health check in Flask, depending on the level of control and visibility required.
## Option 1: Use an existing view
If you don’t want to add a separate health check route, you can reuse an existing public view in your application. The selected view should fail with an error if a critical dependency, such as the database or another essential service, is unavailable.
## Option 2: Use a dedicated health check view
A dedicated health check route provides a clear and explicit way to verify your app’s health. A simple implementation can execute a lightweight query like `session.execute(text("SELECT 1"))` to confirm the database is reachable. If the connection fails, an exception will be raised, and the route will return an error.
```python theme={null}
from sqlalchemy import text
from .extensions import db
@app.route("/health_check")
def health_check():
with db.sessionmaker() as session:
session.execute(text("SELECT 1"))
return "OK"
```
You can extend this route with additional checks (such as cache or queue connectivity) as your application grows.
## Option 3: Use a health check library
Several libraries can help you implement comprehensive health checks for databases, task queues, caches, email services, and more. One such option is [**Healthcheck**](https://github.com/ateliedocodigo/py-healthcheck), which simplifies defining and managing these checks in a single place.
# Data center locations
Source: https://docs.sevalla.com/service-information/data-center-locations
See all available data center locations and their features.
When you create a new site, application, or database, you can choose from a list of data centers. We recommend choosing the location closest to your target audience to reduce latency and improve speed.
## Application and Database Hosting data centers
When [adding an application](/applications/get-started/add-an-application) or a [database](/databases/get-started/add-a-database), you can choose from 25 data centers:
1. Changhua County, Taiwan (asia-east1)
2. Hong Kong (asia-east2)
3. Tokyo, Japan (asia-northeast1)
4. Osaka, Japan (asia-northeast2)
5. Seoul, South Korea (asia-northeast3)
6. Mumbai, India (asia-south1)
7. Delhi, India (asia-south2)
8. Jurong West, Singapore (asia-southeast1)
9. Sydney, Australia (australia-southeast1)
10. Hamina, Finland (europe-north1)
11. St. Ghislain, Belgium (europe-west1)
12. London, United Kingdom (europe-west2)
13. Frankfurt, Germany (europe-west3)
14. Eemshaven, Netherlands (europe-west4)
15. Zurich, Switzerland (europe-west6)
16. Montréal, Canada (northamerica-northeast1)
17. São Paulo, Brazil (southamerica-east1)
18. Santiago, Chile (southamerica-west1)
19. Council Bluffs, Iowa, USA (us-central1)
20. Moncks Corner, South Carolina, USA (us-east1)
21. Ashburn, Virginia, USA (us-east4)
22. The Dalles, Oregon, USA (us-west1)
23. Los Angeles, California, USA (us-west2)
24. Salt Lake City, Utah, USA (us-west3)
25. Las Vegas, Nevada, USA (us-west4)
## Best data center tips
To choose the most suitable data center for your site or application, start by identifying where the majority of your users or customers are located. Selecting a data center that’s geographically closest to them helps reduce latency, as data travels a shorter physical distance between your server and their devices. This results in faster load times and an overall better user experience.
You can use tools like Google Analytics to view your visitors’ geographic distribution. The **User** > **User attributes** > **Overview** report provides insights into where your traffic originates, helping you make an informed decision about which data center region will deliver the best performance.
In the following example, you can see that the majority of the traffic is coming from the United States. So, choosing a US Central data center would be recommended as that will have the lowest latency for visitors coming from within the United States.
If you have any doubts about which data center to choose, feel free to contact our Support Team, and we’ll help you choose the most suitable location.
# DDoS protection
Source: https://docs.sevalla.com/service-information/ddos-protection
Learn how Sevalla protects every application and site with always-on Cloudflare DDoS protection.
Every application and static site hosted on Sevalla is served through Cloudflare's global network and benefits from always-on DDoS protection by default. This protection is not a per-site setting we turn on or off. It applies automatically to all traffic, runs continuously across Cloudflare's network at no additional cost, and requires no action from you.
## Coverage
Sevalla's Cloudflare integration mitigates distributed denial-of-service (DDoS) attacks at both the network and application layers.
* **Network layer (L3/L4):** Cloudflare's Network-layer DDoS Attack Protection managed ruleset is always enabled and mitigates attacks such as SYN floods, UDP floods, and reflection attacks.
* **Application layer (L7):** Cloudflare's HTTP DDoS Attack Protection managed ruleset is always enabled and mitigates HTTP-based attacks automatically, typically within a few seconds.
* **Always-on:** The protection runs continuously across Cloudflare's network at no extra cost and requires no configuration.
DDoS protection is independent of the [CDN](/applications/cdn) caching setting. Even when CDN caching is disabled for an application, all traffic still routes through Cloudflare and remains protected.
## Security reviews
If you or a client need to confirm DDoS coverage as part of a security review, you can cite the following:
* [Sevalla DDoS protection](https://docs.sevalla.com/service-information/ddos-protection) (this page)
* [Cloudflare DDoS protection overview](https://developers.cloudflare.com/ddos-protection/about/), which confirms always-on, unmetered protection at L3, L4, and L7 for all onboarded properties.
# Disclose a vulnerability
Source: https://docs.sevalla.com/service-information/disclose-a-vulnerability
How to report security vulnerabilities to our team.
We make every effort to secure our customer’s data and eliminate any potential security vulnerabilities on our platform. However, it is possible that a vulnerability may be introduced inadvertently and may be noticed by a security researcher or a user of our platform.
If this occurs, we ask that the person who discovers the vulnerability exercise responsible disclosure and alert our team to the issue privately so that we can respond appropriately to ensure the security of our platform and the protection of our customer’s data.
If you discover a security vulnerability on our platform, please send an email to [security@kinsta.com](mailto:security@kinsta.com) to disclose the vulnerability. Include the full details of the vulnerability as well as sufficient information so that our Engineering team can get in touch with you if they need additional information.
## Does Sevalla have a bug bounty program?
Sevalla does not have a bug bounty program.
Bug bounty programs may lead to the discovery of significant vulnerabilities. However, they do also tend to attract attention from a small subset of security researchers who are more interested in extorting a company for financial gain than in improving the security of the platform they are researching. As a result, it is Sevalla’s policy not to pay for the disclosure of security vulnerabilities.
## How are security vulnerability reports handled?
Sevalla’s Engineering team reviews all submitted reports of security vulnerabilities on a daily basis. Each report is evaluated, and our team determines if an actual vulnerability exists.
When an actual vulnerability is discovered, our team will work to resolve the vulnerability as soon as possible.
While our team may reach out to you to gather more information following the submission of a security vulnerability report, we cannot guarantee that we will be able to respond to each submitted report.
# Files and database storage
Source: https://docs.sevalla.com/service-information/files-and-database-storage
Learn about Sevalla's file and database storage management.
When you host a site, application, or database with Sevalla, you can choose the [data center](/service-information/data-center-locations/) where it is hosted. Your files, including backups, are stored in that data center. We do not create copies and store those copies elsewhere.
However, certain pieces of data related to your site’s visitors, files, and database will necessarily leave that data center in a few scenarios. In this article, we’ll explain those scenarios.
## Sevalla tools
In some rare cases, data may be processed by a third party. Such is the case if you enable Sevalla’s CDN in Sevalla. When you do that, you’re enabling a premium CDN powered by Cloudflare, which will then log the requests from your service's visitors as those visitors pull your website’s static asset files over their CDN network.
## Communication tools
If you share data that contains visitors’ information in a chat with our Support team, that data is then stored on our chat provider’s servers. The same is true for any other communication system integrated into our platform or used by our team to provide services.
## Sevalla’s CDN and edge caching
For every service where [Sevalla’s CDN](/applications/cdn/) is enabled, as visitors access your site, copies of your site’s static assets (JavaScript files, CSS files, media files, etc.) will be stored on Cloudflare’s network. Additionally, if [Edge Caching](/applications/edge-caching/) is enabled on your site(s), the rendered HTML files for all cached pages accessed by visitors to your site(s) will also be stored on Cloudflare’s network.
## Summary
When you pick a data center to host your service at Sevalla, your files, and database we create, are stored at that location. However, in order to provide services, we do have to transfer some limited amounts and types of data to other places, as described in this article.
If you have any further questions about this topic, please refer to our [Terms of Service](https://kinsta.com/legal/terms-service/) and [Privacy Policy](https://kinsta.com/legal/privacy-policy/).
# Guaranteed uptime
Source: https://docs.sevalla.com/service-information/guaranteed-uptime
Read about Sevalla's uptime guarantee and service SLAs.
For more details about our infrastructure and architecture, see:
* [Application and Database Hosting infrastructure](/applications/get-started/infrastructure)
* [Static Site Hosting infrastructure](/static-sites/get-started/infrastructure)
Thanks to the flexibility afforded by the use of a container-based infrastructure, proactive load management by our Engineering team, and the use of best-in-class cloud providers, we are able to offer an [SLA-backed 99.9% uptime guarantee](https://kinsta.com/legal/service-level-agreement/).
## Maintenance period
Sevalla’s maintenance period is each day, Monday through Sunday, from 2 am to 5 am local time, based on the time zone of the data center in which each application is hosted. We do not send monitoring notifications if maintenance is performed during this time. For more information, refer to [Sevalla’s Service Level Agreement](https://kinsta.com/legal/service-level-agreement/).
# Service information - Overview
Source: https://docs.sevalla.com/service-information/overview
Overview of the Sevalla service and the difference between Sevalla and MyKinsta.
Sevalla is a Kinsta platform purpose-built for Application, Database, and Static Site Hosting. Designed with developers in mind, Sevalla offers the flexibility and scalability needed for modern web projects. It supports a wide range of use cases, from lightweight static sites to complex, API-driven applications, and includes powerful features such as Object Storage, prebuilt Templates, Git-based deployments, custom domains, and automated scaling.
MyKinsta, on the other hand, is tailored specifically for Managed WordPress Hosting. If your focus is on hosting WordPress websites, MyKinsta provides a streamlined, performance-optimized environment backed by a suite of WordPress-specific tools. These include automatic daily backups, staging environments, built-in caching, free CDN and SSL, and expert WordPress support.
While it’s technically possible to host a WordPress site as a custom application on Sevalla, Managed WordPress Hosting is only available through MyKinsta. Managed hosting offloads much of the technical maintenance, such as updates, security patches, and server optimization, so you can concentrate on content, marketing, and growing your business.
In short:
* Choose Sevalla for apps, databases, and static sites with maximum control and modern tooling.
* Choose MyKinsta for dedicated, worry-free WordPress hosting.
To learn more about WordPress Hosting features, visit [Kinsta.com](https://kinsta.com/).
# Prohibited content
Source: https://docs.sevalla.com/service-information/prohibited-content
List of prohibited content and acceptable use policies.
Our [Terms of Service](https://kinsta.com/legal/terms-service/#h-4-customer-content) outlines several types of content that cannot be hosted at Sevalla, it also outlines customer obligations and acceptable use, such as compliance with laws and what determines malicious activity. In this article, we’ll review a couple of types that we receive the most questions about.
## Adult content
Content that is pornographic, sexually obscene, sexually exploitative of children, or otherwise sexually explicit is not allowed. If you’re not sure whether or not your content is adult content, open a chat with our Support team, and we can let you know if it can be hosted at Sevalla.
## Video hosting or streaming
Video hosting is allowed at Sevalla if you’re hosting one of the following an application or site on our [Application Hosting](https://sevalla.com/application-hosting/).
Third-party video hosting services such as [YouTube](https://www.youtube.com/), [Vimeo](https://vimeo.com/), [Wistia](https://wistia.com/), etc. are usually good alternatives. For more options for offloading videos and other bandwidth-intensive files, see our guide on [How to Optimally Offload PDF, DOCX, and MP3 Hosting](https://kinsta.com/knowledgebase/pdf-mp3-hosting/).
## Other content
We recommend reviewing our Terms of Service if you’re unsure about your content. If that doesn’t answer your questions, please open a chat with our Support team and provide details about your content, and we’ll let you know if it can be hosted at Sevalla.
If you have a query about hosting any website or content related to cannabis (including Marijuana, Hemp, CBD, & THC), please [contact our Support team](/support/contact-support/).
# Russian accounts and domains
Source: https://docs.sevalla.com/service-information/russian-accounts-and-domains
Special information for accounts and domains from Russia.
We are no longer accepting new clients from Russia. This applies only to new clients; at this time, we are permitting existing clients to remain on the platform provided they comply with our Terms of Service. Also, we are not permitting the addition of new domain names that include the top-level domain for Russia (.ru) to our platform.
Our [Terms of Service](https://kinsta.com/legal/terms-service/) disallow the promotion of violence or harm against any individual or group as well as the spreading of false, misleading, or deceptive information. Any Client engaged in violations of our Terms of Service will have their use of our Services terminated.
We decided not to allow new account creation from Russia based on several factors, one being economic sanctions levied by the United States and many other countries as a result of the invasion of Ukraine. Also, many internet infrastructure companies are discontinuing services in and to Russia, which impacts our ability to provide services to the country.
In light of these developments, we cannot accept new clients from Russia at this time.
# Security roles and responsibilities
Source: https://docs.sevalla.com/service-information/security-roles-and-responsibilities
Learn about security roles and responsibilities on our platform.
This article outlines the security responsibilities for the various aspects of Sevalla as a cloud service provider.
| | **Static Site Hosting** | **Application Hosting** | **Database Hosting** |
| --------------------------------------------- | ----------------------- | ----------------------- | -------------------- |
| **User account** | Customer | Customer | Customer |
| **User management and access** | Customer | Customer | Customer |
| **Site, application, and database resources** | N/A | Customer | Customer |
| **Content** | Customer | Customer | Customer |
| **Git access** | Customer | Customer | Customer |
| **Network and infrastructure** | Sevalla | Sevalla | Sevalla |
## User account
It is your responsibility as a customer to manage your user account. This means you are responsible for keeping your credentials safe and using strong passwords to prevent your login details from being compromised. Sevalla allows you to protect your login details even further with [Two-Factor Authentication (2FA)](/user-settings/logging-in/#enable-two-factor-authentication-2fa), which you can enable within [Sevalla](https://app.sevalla.com/) > **User Settings** > **My Account**.
## User management and access
Company Owners and Company Administrators have access to add and remove users at any level. Company Developers can view the company users and grant users access to services. It is your responsibility to ensure all users who have access to your company and services have the correct access level. Find out more in [User Management](/company-settings/user-management/).
## Application, and database resources
If you’re hosting an application with Sevalla, you must ensure you choose the correct build resources and pod size to support your application. If you’re hosting a database with Sevalla, you must ensure you choose the correct database size.
## Content
You, as a customer, are responsible for all content on your services, and you must comply with [Sevalla’s Terms of Service](https://kinsta.com/legal/terms-service/), which includes a list of prohibited content. Sevalla has no obligation to monitor, validate, correct, or update your content in any way. However, if any content violates Sevalla’s terms of service, Sevalla may, in its sole discretion, alter, remove, or refuse to display it.
## Git access
If you use Application or Static Site Hosting, you can connect to a Git provider and authorize/grant access to Sevalla to verify your identity and access your Git repositories. You can also use your Git service provider login with [Single-Sign-On (SSO)](/user-settings/logging-in/#single-sign-on-sso) to sign up or log in to Sevalla. Sevalla does not store your Git credentials, and it is your responsibility to keep them safe.
## Network and infrastructure
With our Cloudflare integration, Sevalla customers benefit from a more secure firewall with included DDoS protection, high-performance CDN, Edge Caching, HTTP/3 support, and more.
Thanks to the flexibility afforded by the use of a container-based infrastructure, proactive load management by our Engineering team, and the use of best-in-class cloud providers, we are able to offer an [SLA-backed uptime guarantee of up to 99.99% ](https://kinsta.com/legal/service-level-agreement/). For more details about our infrastructure and architecture, see:
* [Application and Database Hosting infrastructure](/applications/get-started/infrastructure)
* [Static Site Hosting infrastructure](/static-sites/get-started/infrastructure)
# SOC 2 Type II
Source: https://docs.sevalla.com/service-information/soc-2
Learn about our SOC 2 compliance and audits.
SOC 2 is a standard created by the AICPA (Association of International Certified Professional Accountants). SOC stands for System and Organization Controls (formerly Service Organization Controls). This standard is used to evaluate a service organization’s adherence to one or more [trust services criteria](#what-are-trust-service-criteria).
## How do I get a copy of Sevalla’s SOC 2 report?
Visit our [Trust Report](https://trust.kinsta.com/) page and click any of the request access buttons. In the modal/pop-up that appears, enter the requested information, review and accept our Confidentiality and Non-Disclosure Agreement (NDA), and click **Request access** to submit your request. If you only need access to one doc, select “Access to individual documents” and choose the document(s) you want. If you need access to all of the documents, leave “Full access” selected in the form.
## What is SOC 2 certification?
When discussing SOC 2 compliance, it is sometimes incorrectly referred to as “certification.” No certificate is issued for SOC 2 compliance, so it isn’t really a certification. Instead, a report is created that details the organization’s compliance with one or more [SOC 2 trust services criteria](#what-are-trust-service-criteria).
## Who decides if you’re compliant?
An independent auditor evaluates the service organization’s compliance with one or more [SOC 2 trust services criteria](#what-are-trust-service-criteria). This evaluation is performed at either a specific point in time (Type I) or over a period of time (Type II). [BARR Advisory](https://www.barradvisory.com/) is Sevalla’s auditor, and [Vanta](https://www.vanta.com/) is our GRC (Governance, Risk Management, and Compliance) Management Software.
## What are the different types of SOC 2 reports?
A Type I report describes the security measures in place at a specific point in time. A Type II report (the type of report we have at Sevalla) assesses the effectiveness of those security measures over a period of time.
## What are trust service criteria?
The five trust services criteria (formerly Trust Services Principles) are:
* Security
* Availability
* Processing integrity
* Confidentiality
* Privacy
## Why is SOC 2 compliance important?
When evaluating a service provider for your website, application, or database, you need to know that you can trust them with your data. Our SOC 2 compliance report provides independent proof of our commitment to security. It shows that we have established security procedures and adhered to those procedures over time.
# System status
Source: https://docs.sevalla.com/service-information/system-status
Check real-time system status and incidents.
You can find our status page [here](https://status.sevalla.com/), showing the operational status for all data centers, our website, and Sevalla.
Major outages are reported on the status page. Issues affecting a small number of customers are reported directly to those customers in Sevalla. If you’re experiencing an issue you do not see reported on the status page, please log in to Sevalla to view any alerts our team has added.
## Subscribe to status updates
Subscribe to status updates by clicking on the **Subscribe to Updates** button in the upper right corner of the [status page](https://status.sevalla.com/).
## Unsubscribe from status updates
To unsubscribe from status updates:
* **Email notifications**: On the [status page](https://status.sevalla.com/), click **Subscribe to Updates**, enter your email address, click **Subscribe via Email** > **Unsubscribe from Updates** > **Unsubscribe from Updates**.
* **Text message notifications**: [Contact the Sevalla support team](/support/contact-support/).
# Sevalla API
Source: https://docs.sevalla.com/sevalla-api/overview
Overview of Sevalla's API.
[Sevalla’s REST API](https://api-docs.sevalla.com/) (Application Programming Interface) gives you a simple yet powerful way to access and interact with your Sevalla projects. It streamlines working with our platform, making it easy to retrieve data, perform actions, and automate tasks efficiently.
For full details on available API endpoints, to download our OpenAPI specification, and to try out endpoints, see our [API reference](https://api-docs.sevalla.com/).
## Authentication and user access (API key)
To use Sevalla’s API, you need to generate an API key to authenticate and access your account through the API. You can generate multiple API keys.
Generate an API key from your [Sevalla dashboard](https://app.sevalla.com/api-keys) > **Integration** > **API keys** > **Create API key**. This key authenticates all API requests.
Pass your API key as a Bearer token in the `Authorization` header:
```bash theme={null}
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.sevalla.com/v3/applications
```
Browse the endpoint reference in the sidebar of the [API reference docs](https://api-docs.sevalla.com/). Each endpoint includes request and response schemas, parameter details, and code examples you can copy directly into your project.
Use the **Try it** console on any endpoint page to make live API calls. You'll need your API key and any required parameters for the endpoint you want to test.
When the API key is provided, **this is the only time you can see it**. Make sure you **copy it and store it somewhere safe**.
To remove an API key, click the ellipsis (three dots) and click **Delete**.
## API permissions
When creating an API key, you can choose a predefined role or define custom capabilities. **Predefined role** matches the existing roles available in [User management](https://docs.sevalla.com/company-settings/user-management#user-roles). **Custom capabilities** allow you to define precise permissions, such as create, read, update, or delete, at both the resource type and individual resource level.
For example, you can grant read-only access to specific applications or allow update access to selected sites only.
## Rate limits
To protect our API from being flooded with too many requests, the number of requests per minute is limited to the following:
* 120 requests per minute per company ID identified from the API key.
* 1000 requests per minute per IP address. This would come into force if you have access to multiple companies.
* 5 requests per minute for resource creation.
To see your current rate limit status, check the RateLimit headers in the most recent API response. It is not currently possible to increase the rate limit.
# Static Sites - Analytics
Source: https://docs.sevalla.com/static-sites/analytics
See analytics and usage metrics for your static sites.
Static Site Hosting is free for the first 100 GB of bandwidth per month and 600 build minutes per month; after that, pricing is usage-based, and you only pay for resources if your sites exceed the free limits. For more information, refer to [Static Site Pricing](/billing/static-site-pricing).
If your static sites exceed the free limits, the billing amounts are also included in the **Spending overview** chart within your Sevalla **Dashboard**. This chart shows the spending overview for all Sevalla services.
Static site analytics within each site shows you information about HTTP requests to your site.
When viewing the analytics, you can choose to see data for the past 1 hour, 6 hours, 12 hours, 1 day, 2 days, 4 days, 7 days, 14 days, or 30 days, or select a specific date and time period. You can refresh the chart data at any time.
When you hover over a chart, a corresponding reference line appears on the other charts on the same page. You can click and drag this reference line to zoom into a specific time period, and all charts on the page will update to show that same time range.
You can filter the charts using **Add filter**. This filters all of the charts on the page. The following options are available:
* Source IP
* Country
* Device type
* HTTP method
* Path
* User agent
* HTTP version
* Status code
To access these reports, go to your static site's **Analytics** page (**Static sites** > ***sitename*** > **Analytics**).
## Requests volume by country
The Requests volume by country chart displays the number of requests, ranked by the country from which they originated. You can zoom in and out of the map, and hover over a country to see the exact number of requests from that location. You can also filter the chart to include or exclude specific countries.
## Requests per minute
The Requests per minute chart shows the average number of HTTP requests per minute (RPM) of all HTTP requests for the time period selected.
## Bandwidth
The Bandwidth chart shows your bandwidth usage over the selected timeframe.
## Response time
The Response time chart shows the average response time for all HTTP requests for the time period selected.
## Status codes
The Status codes chart displays the total number of each status code returned for requests. This is useful for analyzing your site to identify when requests return codes other than 200.
## Slowest requests
The Slowest requests table shows the 10 slowest requests to your site for the selected time period and the average response time it took to complete.
## Top pages
The Top pages table shows the top 10 most requested paths by the number of views for your site.
## Additional notes
Analytics data is retained for 30 days. We suggest checking your **Static Site Analytics** frequently after first deploying to Sevalla and periodically after that. If you see any unexplained analytics data or inconsistencies that concern you, you should further investigate to determine the cause.
# Static Sites - Deployments
Source: https://docs.sevalla.com/static-sites/deployments
Manage and monitor deployments of your static sites.
Within **Deployments**, you can see where your static site is deploying from, including the branch, a link to the latest deployment, and if automatic deployments are enabled or not. If automatic deployment is enabled, the site deploys every time a commit is made to the branch in the Git repository. You can enable or disable automatic deployments in the [static site’s Settings](/static-sites/settings).
Static Site Hosting includes 600 build minutes and 100 GB of bandwidth per month per company. If either of these are exceeded, deployments, redeployments, and [automatic deployments](/static-sites/settings#edit-details) are disabled for the rest of the month. For more details, see the full list and descriptions of our [Static Site Features](/static-sites/get-started/features).
Click **View** to open your static site.
## History
In this section, you can see a list of all the previous deployments. You can also manually deploy the static site by clicking **Deploy now**.
If you click on any of the deployments here, you’ll be brought to a dedicated page that shows the **Deployment details** and **Deployment progress**.
### Individual deployment details
If you click on any of the previous deployments, you’ll be brought to a dedicated page that shows the deployment log and **Deployment details** for that specific deployment. If the deployment fails, check the deployment log to identify where the process may have failed.
#### Deployment log
When you deploy your site to Sevalla, the deployment log shows each step of the deployment and whether it is successful or not. For example, you may see the following steps in the deployment log:
1. Fetching source code from GitHub.
2. Source code fetched successfully.
3. Node version set successfully.
4. Packages installed successfully.
5. Build command succeeded.
6. Static site has been deployed successfully.
If the deployment fails at any stage, the logs show an error message indicating why. For information about how to troubleshoot the errors, refer to [Troubleshooting](/static-sites/troubleshooting).
Deployment logs are stored for up to 30 days.
#### Deployment details
This shows information about the deployment, including:
* The name of the Git repository and branch.
* The Commit ID, with a link to the commit at the Git service provider.
* Who initiated the deployment.
* The commit message.
* The deployment start date and time.
* The time it takes for the deployment to finish (**Deploy time**).
* The deployment type is either manual or automatic. Automatic deployments only occur if you have selected **Automatic deployment on commit**.
To redeploy the site from this commit, click **Redeploy**.
# Static Sites - Domains
Source: https://docs.sevalla.com/static-sites/domains
Add and configure custom domains for your static sites.
When you host your static site with Sevalla, it's automatically assigned a free sevalla.page domain as the primary domain upon successful deployment. This allows you to build, test, and preview your site before connecting your custom domain.
When you're ready to make your site live, you can add your custom domain on the **Domains** page. Every custom domain you add automatically includes a free SSL certificate. The temporary sevalla.page domains are automatically covered by the wildcard certificate of sevalla.page domain. (\*.sevalla.page). You can also add a custom SSL certificate.
Newly created static sites use the sevalla.page temporary domain. As Sevalla is a [Kinsta](https://kinsta.com) product, we previously used kinsta.page temporary domains for static sites. This is a normal part of the Sevalla experience. Your static site will still be accessible and manageable through Sevalla's interface even if it uses the kinsta.page domain.
## Add domain
In [Sevalla,](https://app.sevalla.com/) go to **Static sites** > ***sitename*** > **Domains**.
Click **Add custom domain** and enter your domain name. If you want to cover all subdomains, select **Wildcard** and then click **Add custom domain**.
If you add your domain without the wildcard subdomain, you should also consider adding the www version of the domain without the wildcard to ensure both versions are correctly configured.
## Verify domain
To verify your domain, you need to add the records shown to your domain's DNS records: an ownership TXT record, plus an SSL validation record whose type depends on your domain. Some DNS providers, such as [Namecheap](https://www.namecheap.com/), [Spaceship](https://www.spaceship.com/), and [Squarespace](https://www.squarespace.com/) need the short version of DNS record names. Sevalla automatically provides both the full and short versions of each record, so you can use whichever format your DNS provider needs.
**Ownership record (TXT)**
This TXT record allows Cloudflare to verify that you own the domain and are authorized to use their services for that domain. Once the domain is fully validated, you can remove this record from your DNS if necessary.
* Type: `TXT`
* Name: `_cf-custom-hostname`
* Value: Unique UUID value from Sevalla (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
**SSL validation record (`_acme-challenge`)**
Sevalla uses this DNS entry to issue and renew your SSL certificate. As long as this record exists in your DNS, you won't need to manually renew your SSL certificate; Sevalla manages it for you. We don't recommend removing this DNS entry, as you will need to re-add it each time the SSL certificate requires renewal.
The record **type depends on whether your domain is a wildcard**. Add it exactly as Sevalla shows it:
* **Standard (non-wildcard) domains** - add a **TXT** record:
* Type: `TXT`
* Name: `_acme-challenge`
* Value: the validation token shown in Sevalla
* **Wildcard domains** - add a **CNAME** record:
* Type: `CNAME`
* Name: `_acme-challenge`
* Value: `example.com.[unique verification token].dcv.cloudflare.com`
Allow 5-10 minutes for DNS to propagate. If propagation doesn't occur as expected, you can use a DNS lookup tool, such as [dnschecker.org](https://dnschecker.org/) or [mxtoolbox.com](https://mxtoolbox.com/), to verify if the record is resolving correctly.
## Point domain
Once your domain is successfully verified, you can point it by adding the required A records to your domain's DNS settings.
Some DNS providers, such as [Namecheap](https://www.namecheap.com/), [Spaceship](https://www.spaceship.com/), and [Squarespace](https://www.squarespace.com/), need the short version of DNS record names. Sevalla automatically provides both the full and short versions of each record, so you can use whichever format your DNS provider needs.
If you select the **Wildcard** option, an additional A record for `*.yourdomain.com` appears to add to your domain's DNS settings, which ensures all subdomains are covered.
When the domain is successfully pointed, a success message appears.
### Point WWW domain
We recommend that you point the www version of your domain to Sevalla (if you haven't already). To do so, add the www version of the domain to Sevalla and repeat the steps to verify and point the subdomain.
## Proxying through your own Cloudflare (Orange-to-Orange)
Sevalla's infrastructure already runs behind Cloudflare. If your DNS is also on Cloudflare and you enable the proxy (orange cloud) on the records that point to Sevalla, your traffic passes through two Cloudflare zones - your own and Sevalla's. This is known as an Orange-to-Orange (O2O) setup, and it comes with trade-offs:
* **SSL certificate renewal problems:** Sevalla issues and renews your SSL certificate through the `_acme-challenge` record. When your zone proxies the domain, renewal validation can fail, which can leave your domain with an expired certificate. Always keep the verification records (`_cf-custom-hostname` and `_acme-challenge`) set to **DNS only** (grey cloud).
* **Caching issues:** Your Cloudflare zone caches content in front of Sevalla's [edge network](/static-sites/overview), which already serves your static site from 260+ locations. Purging or redeploying in Sevalla does not purge your own zone's cache, so visitors can be served stale content, and conflicting cache rules between the two layers can cause unexpected behavior.
For most setups, we recommend leaving the records that point to Sevalla set to **DNS only** (grey cloud) and relying on Sevalla's built-in edge delivery instead. If you keep the proxy enabled, purge the cache in your own Cloudflare zone as well whenever you redeploy or troubleshoot stale content.
## Change your primary domain
In the domains list, locate the domain you want to be the primary domain, click the kebab (three-dot) menu, and click **Make primary domain**. Verify that the correct domain is selected, then click **Continue**.
## IP address
The IP address is shown when you point your domain. We use Cloudflare to secure our hosting infrastructure, so the corresponding IP you see for your application is a Cloudflare IP address. This means the owner of the IP address is Cloudflare, Inc., located in the United States of America.
The IP address doesn't reflect the physical place where your application is hosted, nor does it add any further latency to your application. Your application files are stored in the [data center location](/service-information/data-center-locations/) you choose. We do not create copies of your application and store those copies elsewhere.
We do not offer dedicated IP addresses because they aren't necessary for most configurations. Since our infrastructure is secured by Cloudflare, sites, applications, and databases hosted on Sevalla use a range of shared IP addresses provided by Cloudflare. Our Cloudflare IP addresses are reserved for Sevalla customers only, so you won't share an IP address with spam or adult sites or applications hosted elsewhere.
## Troubleshoot domain issues
Most domain problems happen during verification or pointing, and they usually come down to a conflicting or mis-entered DNS record. Work through the checks below in order.
### Domain won't verify
If your domain stays unverified after you've added the records Sevalla shows, check the following:
* **Remove any existing A or CNAME record on the root domain.** If your domain already has an A or CNAME record (for example, pointing to a previous host), Cloudflare tries to verify ownership through that record, and verification fails. Remove the old A or CNAME record before verifying, then add the records Sevalla provides.
* **Confirm the `_acme-challenge` record uses the correct type.** The required type depends on whether the domain is a wildcard. For a standard (non-wildcard) domain, add `_acme-challenge` as a **TXT** record. For a wildcard domain, add it as a **CNAME** record (its value ends in `dcv.cloudflare.com`). Always match the exact record type Sevalla shows - using the wrong type prevents the SSL certificate from being issued.
* **Disable the Cloudflare proxy on the verification records.** If you use Cloudflare as your DNS provider, set the verification records to **DNS only** (grey cloud). Proxied (orange cloud) records don't resolve publicly, so verification can't complete. You can re-enable the proxy on your A or CNAME records after the domain is active.
* **Remove conflicting or stale records.** If you previously added and removed this domain in Sevalla, an old `_cf-custom-hostname` TXT value may still be in your DNS. Delete any outdated `_cf-custom-hostname` or `_acme-challenge` records and re-add the exact values shown in Sevalla.
* **Confirm the value matches exactly.** Copy the value directly from Sevalla. A trailing space, a missing character, or a wrong record name causes verification to fail.
* **Check the Time-to-Live (TTL) setting.** This controls how long internet providers and other services remember your DNS settings before checking for updates. It is usually set to Auto or 5 minutes, but if it has been changed to a longer period, DNS propagation can take longer to take effect.
Allow 5-10 minutes after each change for DNS to propagate. Use [dnschecker.org](https://dnschecker.org/) or [mxtoolbox.com](https://mxtoolbox.com/) to confirm a record resolves before assuming it's wrong.
### SSL certificate isn't issued
Sevalla issues and renews your SSL certificate automatically once the domain is verified. If the certificate stays pending:
* Keep the `_acme-challenge` record in place (a TXT record for standard domains, or a CNAME record for wildcard domains). Removing it stops Sevalla from renewing your certificate, and you would need to re-add it.
* Check for a CAA record conflict, described in **Fix domain error** below.
### Fix domain error (CAA record conflict)
During the domain verification process, if a **Fix domain error** button appears next to the domain, this means a CAA record conflict is occurring.
A CAA record is an optional DNS record that lets you specify which certificate authorities (CAs) are allowed to issue SSL certificates for your domain. If a domain has no CAA records, any CA can generate an SSL certificate for it if requested. If a domain has a CAA record, only the CA(s) specified in the CA record can generate an SSL certificate for the domain.
To resolve this error, click the **Fix domain error** button and update the CAA record as indicated in the modal/pop-up. Alternatively, if you do not need a CAA record on your domain, you can remove the CAA record.
### Domain verified, but the site doesn't load
If the domain verifies but doesn't serve your site:
* Confirm the A record (or CNAME) matches the exact value shown on the **Point domain** step in Sevalla. If you reused an old record, update it.
* If you use the Cloudflare proxy, make sure it's enabled only on the A or CNAME records that point to Sevalla, not on the verification records.
* For wildcard domains, confirm you also added the `*.yourdomain.com` A record.
### Check your DNS records
You can see what's actually published for your domain with these commands:
```bash theme={null}
dig +short yourdomain.com A # Existing A record (remove before verifying)
dig +short yourdomain.com CNAME # Existing CNAME (remove before verifying)
dig +short _cf-custom-hostname.yourdomain.com TXT # Ownership TXT - must match the value in Sevalla
dig +short _acme-challenge.yourdomain.com TXT # SSL validation - standard (non-wildcard) domains
dig +short _acme-challenge.yourdomain.com CNAME # SSL validation - wildcard domains
```
If the published values don't match what Sevalla shows, update your DNS records and wait for propagation. If they match and the domain still won't verify, [contact our Support Team](https://docs.sevalla.com/support/contact-support).
# Static Sites - Environment variables
Source: https://docs.sevalla.com/static-sites/environment-variables
Set up environment variables for your static sites.
Environment Variables are useful for feeding the build process of your static site information from outside of your site’s code. This allows for information like API keys to be stored and provided securely, rather than in your site’s code as clear text.
## Special characters in environment variables
In the environment variable keys, you can only use a-z, 0-9, or underscore (`_`). Environment variable values are applied literally, with the exception of parentheses, commas, and double quotes.
### Parentheses
Parentheses can cause the [build and rollout process to fail](/applications/troubleshooting/failed-deployment/#failed-rollout). They cannot be used in environment variables.
### Commas
Unescaped commas are interpreted as delimiters and cannot be used in environment variables.
* For example: `write_stock,read_orders` will cause the rollout process to fail.
* To keep a comma inside a string, escape it with a backslash (`\`) like this: `write_stock\,read_orders` — which will be applied as `write_stock,read_orders`.
### Double quotes
Unescaped double quotes are either disregarded or will cause the rollout process to fail.
* For example, `"my_example_variable"` will be applied as `my_example_variable`.
* To keep double quotes around a variable, escape them with a backslash (`\`) like this: `\"my_example_var\"` — which will be applied as `"my_example_var"`.
* If double quotes are inside of a string (e.g. `my_exampl"e_text`), the [rollout process will fail](/applications/troubleshooting/failed-deployment/#failed-rollout).
* To keep double quotes inside a string, escape them with a backslash (`\`) like this: `my_examp\"le_var` — which will be applied as `my_examp"le_var`.
## Add environment variables
You can add environment variables in the **Build settings** step when [adding a static site](/static-sites/get-started/add-a-static-site) or on your site’s [**Settings page**](/static-sites/settings) after deployment.
You can reference another environment variable using the `${key}` format. For example, to reference an environment variable with the key `DB_PASSWORD` use `${DB_PASSWORD}`.
### In build settings
To add environment variables when adding your site, expand the **Environment variables** section and enter the key-value pairs.
### After deployment
To add environment variables after deployment, go to **Environment variables**, and click **Add environment variables**. Add the key-value pairs and click **Add environment variables**.
If you enable [pull request previews](/static-sites/settings#pull-request-previews), you can select whether to use the environment variables in the production environment, preview environment, or both.
If you add or update an Environment variable, you must redeploy the site.
## Edit environment variables
You can edit variable names (keys) or values within **Environment variables**. To edit a variable, click the ellipsis (three dots), click **Update**, make your changes, and click **Update environment variable**.
# Add a static site
Source: https://docs.sevalla.com/static-sites/get-started/add-a-static-site
Learn how to add a new static site to your account.
With Static Site Hosting, you can easily build and host your static site at Sevalla. Static Site Hosting is available for everyone in [Sevalla](https://app.sevalla.com/). You can add up to 100 sites per company. For more information, see the list of [Static Site Features](/static-sites/get-started/features).
To help get you started and provide examples of minimal applications, you can use one of the Sevalla one-click templates from your **Dashboard** or from **Templates**. To access these templates, you must have a valid payment method on your account.
Click on one of the template options, and this automatically starts the deployment.
## Adding a static site
To add a new static site, click **Add site** on the **Static Sites** page.
The first time you add a static site, you'll need to select a Git service provider and repository from your account. You can choose from any (or all) of the following:
* [Bitbucket](/applications/git/bitbucket)
* [GitHub](/applications/git/github)
* [GitLab](/applications/git/gitlab)
Once you've connected your Git provider account, you'll be returned to Sevalla to continue with the rest of the **Add static site** steps.
### Static site details
* **Repository:** Select the Git repository to use.
* **Branch:** Set the branch that will be deployed on commit or manually.
* **Name:** This name will be displayed in Sevalla for easy reference. The name must be unique; it cannot be the same as another static site, [application](/applications/get-started/add-an-application), or [database](/databases/get-started/add-a-database).
* **Project:** This option is only shown if your company already has at least one project. Select the project you’d like to add the static site to, or leave it blank to keep the site at the company level instead of assigning it to a specific project.
### Deployment settings
* **Auto-deploy:** Select this to automatically deploy your site each time a commit is made to the branch selected above.
* **Pull request previews:** Enable you to preview your site, allowing you to review changes before deploying them to your site. To enable pull request previews, select **Enable pull request previews**.
If you enable pull request previews, this creates a new deployment for each pull request, which will increase your build minutes and bandwidth usage.
When Pull Request Previews are enabled, Sevalla automatically creates a **Preview** environment in your Deployments whenever a pull request is merged in your Git provider.
If you push a new empty branch to GitHub, Sevalla does not trigger a deployment. However, if the new branch contains at least one commit, a deployment is automatically triggered.
When you select the deployment, you can click **View previews** to view a preview of the branch or the commit.
If you enable pull request previews, you can select whether to use the [environment variables](/static-sites/environment-variables) in the production environment, preview environment, or both.
### Build settings
The build settings dictate how we build your static site. If your site uses one of the [frameworks we automatically detect](#automatically-detected-frameworks), the **Build command** and **Publish directory** are automatically populated, and a notification that the framework was detected is shown. Double-check the fields to confirm they are correct.
#### Build settings
* **Build site before publishing:** Select this if you want Sevalla to build your site before it’s deployed.
* **Node version**: Optional. If you enter a build command, you can specify which major version of Node.js to use during the build process to ensure compatibility and avoid errors. When you select the major version, Sevalla pulls the latest image for that version during the build. You can also choose, `latest` to use the most up-to-date version and `lts` for the currently active long-term support version.
* **Build command**: Optional. If your static site requires a build command, enter it here.
* **Root directory**: Optional. This field defines the root folder of your static site, which is useful if you have a non-standard folder structure or [monorepo](/applications/reference/glossary#monorepo) setup.
* **Publish directory**: Optional. If this is left blank, it defaults to the root folder of your repository.
If you want to publish your site to a specific subdirectory, enter it here, relative to the repository root.
If you have an HTML site that doesn't need to be built that you want to run from a specific subdirectory, place your site files in that directory and enter it here, relative to the repository root.
* **Index file**: If you use a single-page application (SPA), enter the site's default page. SPAs typically use a single HTML file, commonly named `index.html`. When a user enters a URL for your site, all navigation traffic is directed through the index file to ensure seamless navigation within the site.
* **Error file**: If you use a single-page application (SPA), you can specify which file to redirect traffic to if an error occurs in the navigation.
Specifying a Build command and Publish directory are crucial steps if your site depends on a build step. The Build command tells our system how to assemble your site, and the Publish directory is the subdirectory where the finished site files live, relative to the root of your repository. Filling these out correctly will ensure your site is built and served as you intend. If the Build command is left blank, the system may indicate the deployment is complete, but it will only upload the unbuilt contents of your repository.
#### Automatically detected frameworks
To automatically detect the framework, we check which dependencies are used in the **package.json** file to determine the framework. If one of the following frameworks is detected, then we automatically populate the **Build command** and **Publish directory** fields. We also check for a **yarn.lock** file in the repository, and if one is found, we populate the **Build command** with the equivalent yarn commands instead of npm commands.
| Framework | Build Command | Publish Directory |
| ------------------------------ | --------------------------------------------------------------------- | ----------------- |
| Astro | yarn build
npm run build | dist |
| ElderJS | yarn build
npm run build | public |
| Gatsby | yarn build
npm run build | public |
| Next.js | yarn build
npm run build | out |
| Nuxt | yarn generate
npm run generate | .output/public |
| React (using Create React App) | yarn build
npm run build | build |
| React (using Vite) | yarn build
npm run build | dist |
If you use a different framework that you'd like to be added to the list of automatically detected frameworks, [open a new chat with our Support team](/support/contact-support) and let us know.
#### Environment variables
[Environment variables](/static-sites/environment-variables) securely provide the build process information, like API keys or other details you do not want to include as clear text in your site's code. Add the key-value pairs here for your environment variables. Environment variables can also be added, updated, or removed on the Settings page after your site is created.
Click **Create site** to begin deploying your site.
## View site
Once your site is successfully deployed, you can open the site using **View** at the top of each page within the static site in Sevalla.
# Static Sites - Features
Source: https://docs.sevalla.com/static-sites/get-started/features
Explore features available for static site hosting.
Sevalla's Static Site Hosting is available for **free** and lets you [deploy your static sites](https://sevalla.com/static-site-hosting/) to 260+ locations. Your site's files can be pre-built (HTML, CSS, and JavaScript) or can be the source code to [generate your static site](/static-sites/get-started/static-site-generators). Because static sites do not contain dynamic content, they are more secure and need fewer resources to run.
Static Site Hosting is available for everyone in Sevalla and includes:
* **100 sites per company:** If your company reaches 100 static sites, the [**Add site**](/static-sites/get-started/add-a-static-site) button is disabled. You can delete unused sites to free up spots and add new ones.
* **1 concurrent build per site:** If you initiate a build, you must wait for it to complete before initiating another build.
* **1 GB build image size per site:** The total build image size for a site cannot exceed 1GB. If the build image exceeds 1 GB, the build will fail with an error message that you have exceeded the 1 GB build size.
* **600 build minutes per month per company:** If the total build time for all of your company's sites exceeds 600 minutes in one month, additional build time is billed at \$0.05 per minute; for more information, refer to [Static Site Pricing](/billing/static-site-pricing).
* **100 GB bandwidth per month per company:** If the total bandwidth used across all of your company's sites exceeds 100 GB in one month, additional bytes are billed at a price of \$0.0000000001 per byte (\$0.1 per GB); for more information, refer to [Static Site Pricing](/billing/static-site-pricing).
* **User Management:** You can invite as many [users](/company-settings/user-management) as required to your company or site with different levels of access, depending on their role.
# Go live checklist
Source: https://docs.sevalla.com/static-sites/get-started/go-live-checklist
Checklist to help your static site go live successfully.
Follow the go-live checklist to ensure you have everything ready to get your site up and running quickly on Sevalla's Static Site Hosting. If you run into any problems or have questions, we're happy to help.
To help you get started with Static Site Hosting, you can use one of our [example templates on GitHub](https://github.com/topics/kinsta-static-site-hosting).
## 1. Git service provider
You must ensure your site has been pushed to a Git repository. When you add a static site in Sevalla, you must select a Git service provider and repository from your account. You can choose from any (or all) of the following:
* [Bitbucket](/applications/git/bitbucket)
* [GitHub](/applications/git/github)
* [GitLab](/applications/git/gitlab)
## 2. Build command and publish directory
The [**Build command** and **Publish directory**](/static-sites/get-started/add-a-static-site#build-settings-1) are optional; however, if your site depends on a build step, you must populate these fields when you add your static site. The **Build command** tells our system how to assemble your site, and the **Publish directory** is the subdirectory where the finished site files live, relative to the root of your repository. If the **Build command** is left blank, the site will still deploy, but it will only upload the unbuilt contents of your repository.
We automatically populate the **Build command** and **Publish directory** from the `package.json` or `yarn.lock` files if you're using one of the following frameworks:
* Astro
* ElderJS
* Gatsby
* Next.js
* Nuxt
* React
## 3. Environment variables
Ensure you have all of the required [environment variables](/static-sites/environment-variables) for your site. Environment variables feed your site information from outside your site's code. They typically set things like API keys.
## 4. Add your domain to Sevalla
After you've confirmed your site is all good, it's time to go live with your custom domain. Check out our [Static Site Hosting Domains guide](/static-sites/domains).
# Static Sites - Infrastructure
Source: https://docs.sevalla.com/static-sites/get-started/infrastructure
Learn about the infrastructure supporting static site hosting.
When you [host your static site with Sevalla](https://sevalla.com/static-site-hosting/), your site is pushed to Cloudflare’s Content Delivery Network (CDN) with 260+ locations. A [Content Delivery Network (CDN)](https://kinsta.com/knowledgebase/what-is-a-cdn/) is a geographically distributed network of servers that work together to deliver website content and other digital assets to users. CDNs are designed to improve content delivery’s performance, reliability, and scalability by reducing latency and optimizing data transfer.
Visitors to your site are served from the closest, fastest, and easiest-to-access CDN location, so data processing can occur much closer to the end users. In this guide, we’ll dive a little into the details of our Static Site Hosting infrastructure.
## Deployment
### Git repository
Your static site’s code is stored within a Git repository. You can choose from any (or all) of the following:
* [Bitbucket](/applications/git/bitbucket)
* [GitHub](/applications/git/github)
* [GitLab](/applications/git/gitlab)
### Sevalla add/deploy static site
In Sevalla, when you [add a static site](/static-sites/get-started/add-a-static-site), it connects to the Git repository to retrieve the site.
### Sevalla bot
With Automatic deployment on commit enabled in your [static site’s settings](/static-sites/settings), if you commit a change or merge to your repository, the Sevalla bot detects this, then pulls the site from your Git service provider and deploys the updated version of the site.
### Kubernetes pod
Sevalla communicates with the build service, which creates a Kubernetes Pod. Each pod is a standalone isolated environment for each and every deployment. The Kubernetes pod builds the site and pushes the content to the Cloudflare R2 storage.
## Requests
### Cloudflare R2 storage
Cloudflare R2 Storage is a bucket system that holds all of the files that make up your site. Cloudflare then distributes copies or cached versions of the site to the edge servers within the CDN’s 260+ locations.
### Cloudflare’s Globally Distributed Network (CDN)
Cloudflare’s CDN consists of numerous [edge servers](/static-sites/overview#the-edge) strategically located in various geographic locations close to end users. When a user requests content from your site, the CDN’s edge server closest to the user receives the request. If the requested content is already cached on that edge server, it can deliver it directly to the user without needing access to the origin server.
If the requested content is unavailable on the edge server, the CDN retrieves it from R2 Storage, where the content is stored. The CDN then caches the content on the edge server for subsequent requests, optimizing the delivery process.
The CDN employs load-balancing techniques to distribute incoming traffic across multiple edge servers. This ensures that the load is evenly distributed, reducing the risk of server overload and improving overall performance. Content delivery is further optimized by implementing techniques like intelligent routing, which delivers content to the end user based on factors such as:
* User location
* Network conditions
* Server load and capacity
* Content availability
This smart routing sends content requests to the most optimal edge server within the CDN to deliver your static site efficiently.
# Static site generators
Source: https://docs.sevalla.com/static-sites/get-started/static-site-generators
Guide to supported static site generators and frameworks.
[Static sites](https://kinsta.com/knowledgebase/what-is-a-static-website/) do not contain dynamic content and are composed of static files, such as HTML, CSS, and JavaScript, that do not require server-side processing or a database.
Because the files are pre-built, no further processing is required when a user visits the site and fewer resources are needed to run the site. With no scripts or a database to exploit, the site's security is also increased.
## Benefits of static site generators
If you're familiar with HTML, CSS, and JavaScript, you can build a static site using a [text or code editor](https://kinsta.com/blog/best-text-editors/). However, you need the technical knowledge to write the content, it can be unwieldy and time-consuming, and as your site grows, it can become harder to manage and maintain.
[Static site generators](https://kinsta.com/blog/static-site-generator/) (SSGs) offer a more efficient option to build your static site. They often include various tools that make it easier to create, style, publish, and edit your content as need. Some of the key benefits of using a static site generator are:
* **Templating**: A templating system lets you define the structure and layout of your website using reusable templates and components that can be used across multiple pages. This means you don't need to duplicate or update common elements across multiple pages manually. This also separates your content from the design and presentation layer, so you can focus on writing and updating the content.
* **Automation**: If your site includes content from various sources, such as Markdown files or data files, a static site generator can automate the process of converting your content into HTML files. Tasks like minification, optimization, and asset bundling can also be automated. All of this saves you time and reduces the chances of errors, by allowing you to create and optimize your site without manually performing each task.
* **Version control**: Static site generators integrate with version control systems like Git, so you can track changes, collaborate with others, and easily revert to previous versions if needed.
* **Incremental Builds:** With incremental builds, when you make changes and generate a new output, only the files that have changed since the last build are regenerated. Many static site generators support incremental builds, improving the build time for larger sites and small updates.
## Using a static site generator
Each static site generator (SSG) has its own features, configurations, and templating systems, but the setup to generate a site that will be hosted with Sevalla's Static Site Hosting usually involves the following:
1. **Choose your SSG:** There are many SSGs available. Selecting the one that best suits your needs is the first step. To build and host the site with Sevalla's Static Site Hosting, choose one that uses Node.js for the build process. Below, we have a list of [SSG's ready to use at Sevalla](#static-site-generator-compatibility).
2. **Set up a local development environment:** Install the necessary dependencies, including the SSG itself, any required programming languages, and a code editor.
3. **Create your new site:** In your SSG, create the new site. This generates the basic directory structure and configuration files required for the project.
4. **Configuration:** Set up your site's configuration to customize the site structure and how the generator processes your source files. This file may contain settings like the input and output directories, template paths, metadata, plugin configurations, etc.
5. **Templating:** Create templates and layouts that define common elements and structure for your pages, such as headers, footers, navigation menus, etc.
6. **Add content and assets:** Create or gather existing content using Markdown or other supported formats. Each page generally corresponds to a file within the content directory. Assets will likely be stored in a separate directory from the content files.
7. **Styling:** Modify the CSS or preprocessor files (e.g. SASS or LESS) to apply custom styles to your site. Some SSGs also have themes available that can be installed and customized for styling.
8. **Build and preview locally:** Run the build command provided by the SSG to compile your website. The SSG processes your templates, converts your content files to HTML, and generates the static files (HTML, CSS, and JavaScript). If applicable, it will also perform tasks such as minification, optimization, and asset bundling. Use this setup to ensure that everything looks and functions as intended.
9. **Create your Git repository:** Use Git to create your repository, then commit and push your new site to your new Git repository.
10. If you will be deploying the site to Sevalla without running the build at Sevalla, the files you commit to your repository need to be the output from the build (the HTML, CSS, and JavaScript files).
11. If the site is to be built at Sevalla, the files you commit to your repository need to be the content, assets like images or other media, and the SSG files (or configuration files that will pull in the dependencies for the build).
12. **Deploy your new static site:** In Sevalla, [add a new static site](/static-sites/get-started/add-a-static-site) and connect it to your Git repository to deploy your site to Sevalla's 260+ CDN locations.
13. **Maintain and update:** As you continue to work on your site, make sure to follow best practices for version control, regularly commit changes, and stay updated with the latest versions of the SSG and its dependencies. This ensures a smooth development process and allows you to take advantage of new features and bug fixes.
## Static site generator compatibility
Sevalla's Static Site Hosting is for pre-built static sites or sites built with modern JavaScript frameworks that use Node.js to build the site at Sevalla. Landing pages, brochure sites, and even some small blogs that aren't updated too often and do not require dynamic content (like comments) are usually a good fit.
If your site meets any of the following conditions, it will be better suited for our [Application Hosting](https://sevalla.com/application-hosting/):
* It uses a language other than Node.js to build the site (e.g. PHP).
* It requires server-rendering to serve some or all of the site.
* It requires a [database connection](/databases/connections).
* It serves dynamic content.
* It requires sessions or authentication managed on the server-side.
If you're not entirely sure which hosting would be best for your site, we recommend deploying your site on both to try out each option and determine which best suits your needs.
There are many static site generators available, and the build command and publish directory can vary from site to site. Sevalla [automatically detects several frameworks](/static-sites/get-started/add-a-static-site) and populates the **Build command** and **Publish directory** fields when you're adding your static site.
The table below shows the build command and publish directory to use for various popular static site generators that are compatible with Static Site Hosting.
| Static site generator | Build command | Publish directory | Additional notes | |
| ------------------------------ | ----------------------------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - |
| Angular | npm run build -- -c production | dist/(name\_of\_the\_project) | | |
| Astro | npm run build | dist | | |
| Brunch | npm run build | public | | |
| Build Awesome (Eleventy) | `npx @11ty/eleventy` | \_site | | |
| Cuttlebelle | npm run build | .site | | |
| Docusaurus | npm run build | build | | |
| Elder.js | npm run build | public | | |
| Ember | npm run build | dist | | |
| Gatsby | npm run build | public | | |
| Gridsome | npm run build | dist | Requires Node 16 or enabling OpenSSL legacy provider.\* | |
| Hugo | npm run build | public | Requires additional configuration for compatibility.\*\* | |
| Hexo | npm run build | public | | |
| Next.js | npm run build | out | Create according to \[Next Static Exports]\("[https://nextjs.org/docs/app/building-your-application/deploying/static-exports](https://nextjs.org/docs/app/guides/static-exports)" target="\_blank" rel="noopener noreferrer). | |
| Nuxt | npm run generate | .output/public | Create according to \[Nuxt client side only rendering]\("[https://nuxt.com/docs/getting-started/deployment#client-side-only-rendering](https://nuxt.com/docs/getting-started/deployment#client-side-only-rendering)" target="\_blank" rel="noopener noreferrer). | |
| Preact | npm run build | dist | | |
| Qwik | npm run build & npm run build.server | dist | Requires the \[SSG adapter]\("[https://qwik.dev/docs/guides/static-site-generation/#static-site-generation-config](https://qwik.dev/docs/guides/static-site-generation/#static-site-generation-config)" target="\_blank" rel="noopener noreferrer). | |
| React (using Create React App) | npm run build | build | | |
| React (using Vite) | npm run build | dist | | |
| Solid | npm run build | dist | | |
| Svelte | npm run build | build | Requires the \[static site adapter]\("[https://svelte.dev/docs/kit/adapter-static](https://svelte.dev/docs/kit/adapter-static)" target="\_blank" rel="noopener noreferrer"). | |
| Vite 3 | npm run build | dist | | |
| Vue | npm run build | dist | | |
| VuePress 1.x | npm run build | src/.vuepress/dist | Requires Node 16 or enabling OpenSSL legacy provider.\* | |
| VuePress 2.x | npm run build | ./docs/.vuepress/dist | | |
**\* Gridsome or VuePress 1.x**
This requires Node 16, or you can add the following to the **package.json** for the **Build command:**
```
SET NODE_OPTIONS=--openssl-legacy-provider && vuepress build src
```
**\*\* Hugo**
Add the following to your project:
```
npm install hugo-bin serve --save-dev
```
Add or replace the following, depending on your project:
```
{
"scripts": {
"build": "hugo"
}
}
```
It's common for Hugo themes to recommend installation via a Git submodule. Currently, submodules are not compatible with Static or Application Hosting, so the theme files must be available in the site's repository.
# Static Sites - Glossary
Source: https://docs.sevalla.com/static-sites/glossary
Glossary of terms for static site hosting.
## Bundling
Static site generators often use bundling to combine multiple files into a single file. This usually includes HTML, JavaScript, and CSS files. Bundling may also convert assets like images and fonts into data URLs and add them to the bundle. Reducing the overall number of individual files that need to be downloaded by the browser means fewer requests and, therefore, can result in faster page load times.
## Content Delivery Network (CDN)
A Content Delivery Network (CDN) is a geographically distributed network of servers that work together to deliver website content and other digital assets to users. CDNs are designed to improve performance, reliability, and scalability by reducing latency and optimizing data transfer.
Sevalla’s CDN consists of numerous [edge servers](/static-sites/overview#the-edge) strategically located in various geographic locations close to end users. At Sevalla, we use Cloudflare’s content delivery network (CDN), with 260+ locations for Static Site Hosting.
## Dynamic content
Dynamic content is generated or updated in real time, based on user interactions, database queries, or other external data sources. Unlike static content, which remains the same for all users and requests, dynamic content can vary based on specific conditions or user-specific information. Using dynamic content, websites and applications can adapt to user needs, deliver personalized experiences, and provide real-time updates.
Dynamic content is typically generated through server-side languages (like PHP, Ruby, Python, or server-side JavaScript) or through client-side scripting with JavaScript, which interacts with server APIs or retrieves data asynchronously.
## Intelligent routing
Intelligent routing, also known as smart routing or dynamic routing, optimizes the delivery of content from an edge server within a CDN to a user based on various factors such as:
* User location
* Network conditions
* Server load and capacity
* Content availability
Intelligent routing algorithms employ machine learning techniques and real-time data analysis to make real-time decisions on routing content requests to the most optimal edge server within a CDN to deliver content efficiently.
## Minification
Static site generators often use minification to reduce the size of your site’s HTML, CSS, and JavaScript files by removing unnecessary characters, spaces, line breaks, and comments. This results in smaller files requiring less bandwidth, improving the website’s performance, and reducing download times.
## Server-side Rendering (SSR)
An SSR application is a type of web application architecture where the server processes the request, executes the required logic, generates the HTML content, and sends it back to the client’s browser along with any associated CSS or JavaScript.
## Static content
Static content remains the same for all users and requests. It is pre-defined and doesn’t change based on user interactions or external data sources. Static content is typically stored as files and served as-is to the user without any modifications.
Static content is often stored on a web server or a Content Delivery Network (CDN) and can be easily cached by browsers or proxy servers. Since static content doesn’t change frequently, it can be efficiently delivered to users, reducing server load and improving website performance.
## The Edge
The Edge is a network infrastructure that places content geographically closer to the end users. It extends the capabilities of the cloud by placing computing resources and services closer to the end users or devices at the network’s edge. For more detailed information, see our [Edge documentation](/static-sites/overview#the-edge).
# Static Sites - Headers
Source: https://docs.sevalla.com/static-sites/headers
Find out how to add custom HTTP headers to your static sites in Sevalla.
If a static site has a `_headers` file in the repository's root directory, Sevalla will parse the file's contents and apply the custom header rules to matching responses.
## Header rule format and examples
Each header rule starts with a path on its own line, followed by one or more indented header definitions in the format `Header-Name: value`. Any line beginning with `#` will be treated as a comment and ignored. Paths are case-sensitive.
For example:
```text theme={null}
# Security headers for all pages
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
# Cache static assets for one year
/assets/*
Cache-Control: public, max-age=31536000, immutable
# Custom header for the API
/api/*
X-Api-Version: 2.0
```
Header rules are processed from top to bottom, and all matching rules are applied. If multiple rules match the same path, their headers are combined. When the same header name appears in multiple matching rules, the values are merged with a comma separator.
## Applying headers to all pages
Use the `/*` wildcard pattern to set headers that apply across your entire site:
```text theme={null}
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
```
This is useful for security headers, which typically need to be present on every response.
## Wildcards
An asterisk (`*`) represents a wildcard, which matches any characters in a path, including slashes. For example:
```text theme={null}
/images/*
Cache-Control: public, max-age=86400
```
This applies the `Cache-Control` header to any path under `/images/`, such as `/images/logo.png` or `/images/icons/arrow.svg`.
You can also use wildcards within a path segment to match file extensions:
```text theme={null}
/*.css
Cache-Control: public, max-age=31536000
/*.js
Cache-Control: public, max-age=31536000
```
> **Note:** Wildcards are greedy - `/*.svg` will match both `/logo.svg` and `/images/icons/logo.svg`, as the wildcard crosses directory boundaries.
## Placeholders
You can use placeholders to match a single path segment. A placeholder starts with `:` followed by a name and matches any characters except `/`. For example:
```text theme={null}
/docs/:version/*
X-Docs-Version: latest
```
In this example, the rule matches paths like `/docs/v2/getting-started` or `/docs/v3/api-reference`, but not `/docs/` by itself.
## Combining multiple rules
When multiple rules match a request path, all of their headers are applied to the response. If the same header name appears in more than one matching rule, the values are combined with a comma separator.
For example:
```text theme={null}
/*
Cache-Control: public
X-Custom: global
/api/*
Cache-Control: no-store
X-Api: true
```
A request to `/api/users` matches both rules. The resulting headers would be:
* `Cache-Control: public, no-store`
* `X-Custom: global`
* `X-Api: true`
To avoid conflicting cache directives, place more specific rules carefully and avoid overlapping `Cache-Control` values between wildcard and specific rules.
## Common use cases
### Security headers
```text theme={null}
/*
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Permissions-Policy: camera=(), microphone=(), geolocation=()
```
### Caching static assets
```text theme={null}
/assets/*
Cache-Control: public, max-age=31536000, immutable
/*.html
Cache-Control: public, max-age=0, must-revalidate
```
### Custom headers for an API path
```text theme={null}
/api/*
Access-Control-Allow-Origin: *
X-Api-Version: 2.0
```
### CORS for font files
```text theme={null}
/fonts/*
Access-Control-Allow-Origin: *
```
## Restricted headers
Certain headers are managed by the platform and cannot be overridden. If a restricted header appears in your `_headers` file, it will be silently ignored. The following headers are restricted:
* `Accept-Ranges`
* `Age`
* `Allow`
* `Alt-Svc`
* `Connection`
* `Content-Encoding`
* `Content-Length`
* `Content-Range`
* `Date`
* `Location`
* `Server`
* `Trailer`
* `Transfer-Encoding`
* `Upgrade`
# Static Sites - Networking
Source: https://docs.sevalla.com/static-sites/networking
Configure public networking options for your static site, including cache purging.
On your static site's **Networking** page, you can purge the CDN/Edge cache. To view these settings, go to **Static sites** > ***site name*** > **Networking**.
## Public networking
### CDN/Edge cache
Your static site is served from our global CDN at [the Edge](/static-sites/overview#the-edge). Sevalla automatically purges this cache after every successful deploy, so updated assets are typically served without any manual action.
If updated assets still aren't showing up after a deploy, you can clear the cached assets yourself instead of waiting for the cache to expire. To clear the cache, click **Purge cache**. This purges the CDN/Edge cache for your site, so the latest version of your assets is served. The purge takes effect right away, and you'll get a confirmation once the cache is cleared.
Anyone with update access to the static site can purge the cache.
# Static Sites - Overview
Source: https://docs.sevalla.com/static-sites/overview
Overview Sevalla's Static Site Hosting.
With Sevalla’s Static Site Hosting, you can deploy [static sites](https://kinsta.com/knowledgebase/what-is-a-static-website/) composed of non-dynamic files such as HTML, CSS, and JavaScript. Your repository can contain the pre-built files or the source code to generate your static site.
Sevalla has 260+ CDN locations for Static Site Hosting. Static sites are pushed to [the edge](#the-edge) at these CDN locations. This means visitors to your site are served from the closest, fastest, and easiest-to-access CDN location.
If you need further assistance with Static Site Hosting, to ask Sevalla’s Support, which is powered by Stella, our AI support agent built on Claude, available through the chat system directly inside Sevalla. Stella is the first point of contact for all customers and can resolve most common questions and issues. Customers are initially assisted by Stella, with human support available directly to customers above a certain spending level.
## Git service providers
The first time you [add a static site](/static-sites/get-started/add-a-static-site), you’ll need to select a Git service provider and repository from your account. You can choose from any (or all) of the following:
* [Bitbucket](/applications/git/bitbucket)
* [GitHub](/applications/git/github)
* [GitLab](/applications/git/gitlab)
Once you’ve connected your Git provider account, you’ll be returned to Sevalla to continue with the rest of the **Add static site** steps.
## Features
You can add up to 100 static sites per company. Static sites use fewer resources because they do not require server-side processing or a database. They are also more secure because there are no scripting or database exploits to take advantage of. Check out our [Static Site Hosting Features](/static-sites/get-started/features) for a full list of what Sevalla’s Static Site Hosting has to offer.
## Pricing
Static Site Hosting at Sevalla includes the following for free:
* 100 sites overall
* 600 build minutes per month per account
* 100 GB bandwidth per month per account
* 1 GB build size and 1 concurrent build per site
You cannot increase the number of sites or build size; however, if you exceed the build minutes or bandwidth, the following charges apply:
* **Build minutes**: After the first 600 minutes in a month, the build minutes are \$0.05 per minute.
* **Bandwidth**: After the first 100 GB in a month, the bandwidth is \$0.1 per GB.
For more information, refer to [Static Site Pricing](/billing/static-site-pricing). To estimate your monthly costs, use the [Sevalla pricing calculator](https://sevalla.com/pricing/calculator/).
## The Edge
The Edge is [Cloudflare’s global network](https://www.cloudflare.com/network/) that places content geographically closer to the end users.
In typical cloud computing, data, and processing tasks are sent to centralized servers located in data centers. These servers handle data storage, processing, and delivery for various applications. However, sending data to distant data centers for processing may not be efficient due to factors like latency, bandwidth limitations, or the need for real-time processing.
That’s where the Edge comes in. It extends the capabilities of the cloud by placing computing resources and services closer to the end users or devices at the network’s edge. At Sevalla, we use Cloudflare’s content delivery network (CDN), with 260+ locations for Static Site Hosting.
[Static sites](/static-sites/get-started/add-a-static-site) are pushed to the edge at these CDN locations. Visitors to your site are served from the closest, fastest, and easiest-to-access CDN location so that data processing can occur much closer to the end users. This reduces the time it takes for data to travel back and forth to centralized cloud servers, which enables faster response times, lower latency, and improved performance for sites that require real-time or near-real-time processing.
This makes the Edge ideal for static sites as they consist of [pre-rendered HTML, CSS, and JavaScript files](/static-sites/get-started/static-site-generators) that do not require server-side processing or database queries. They can also handle high-traffic loads more efficiently because they don’t rely on server-side processing. The Edge can serve the content independently, reducing the load on the origin server, improving overall performance, improving site reliability, and reducing points of failure.
Distributing content to the Edge also provides better resilience against network issues, reduces bandwidth requirements, and minimizes data transfer costs, optimizing cost efficiency.
## Dynamic content on static sites
Static sites do not have a backend server to execute server-side code or interact with databases dynamically; therefore, you can’t use dynamic content such as contact forms or a search function directly on a static site. However, you can use API calls from third-party services, such as [Formspree](https://formspree.io/), [Getform](https://getform.io/), or [Meilisearch](https://www.meilisearch.com/), to incorporate dynamic functionalities into your static site.
## Important notes and troubleshooting
If you’re having any trouble deploying your static site, check out our [troubleshooting guide](/static-sites/troubleshooting). Here are some important things to keep in mind:
* Sevalla’s Static Site Hosting is for pre-built static sites or sites built with [modern static site generator frameworks](/static-sites/get-started/static-site-generators#static-site-generator-compatibility) that use Node.js. If your site meets any of the following conditions, it will be better suited for our [Application Hosting](https://sevalla.com/application-hosting/):
* It uses a language other than Node.js to build the site (e.g. PHP).
* It requires server-rendering to serve some or all of the site.
* It requires a [database connection](/databases/connections).
* It serves dynamic content.
* It requires sessions or authentication managed on the server-side.
* You’ll be asked to specify a **Build command** and **Publish directory** during the setup process. The **Build command** tells our system how to assemble your site, and the **Publish directory** is the subdirectory where the finished site files live, relative to the root of your repository. It’s crucial to fill out these fields correctly if your site depends on a build step. This will ensure your site is built and served as you intend. If the **Build command** is left blank, the system may indicate the deployment is complete, but it will only upload the unbuilt contents of your repository.
* If you’re deploying a pre-built site and your files are in a subdirectory of your repository, be sure you’ve entered the path to that subdirectory (where your HTML files and assets are stored) in the **Publish directory** field, relative to the root of your repository.
* The **Build and rollout process** log for each deployment can be viewed on the [Deployment details](/static-sites/deployments) page.
* If a [site is deleted](/static-sites/settings), depending on the caching headers sent by the site and the user’s browsers settings, the deleted site may still appear to be available for a few minutes or hours due to caching.
* A static site’s [**Display name**](/static-sites/get-started/add-a-static-site/) must be unique; it cannot be the same as another static site, [application](/applications/get-started/add-an-application), or [database](/databases/get-started/add-a-database).
# Static Sites - Redirects
Source: https://docs.sevalla.com/static-sites/redirects
Find out how to add redirects to your static sites in Sevalla.
If a static site has a `_redirects` file in the repository's root directory, Sevalla will parse the file's contents and apply the custom redirect rules.
## Redirect rule format and examples
Each redirect rule must be placed on its own line, with the original path followed by the new path or destination URL. Any line beginning with `#` will be treated as a comment and ignored. Paths are case-sensitive, and special characters must be URL-encoded.
For example:
```text theme={null}
# Redirects
/shop /store
/products/item.php /products/item
/events /community/events
/old-dashboard https://example.com/new-dashboard
/team/john%smith%1 /team/about-john%smith%1
```
You can further customize redirect behavior by adding options at the end of each line, such as HTTP status codes, country rules, or language conditions.
### HTTP status code example
Redirect permanently using a `301` status code:
```text theme={null}
/old-page /new-page 301
```
Temporary redirect using a `302` status code:
```text theme={null}
/sale /summer-sale 302
```
### Country rule example
Redirect visitors from France to a localized page:
```text theme={null}
/pricing /fr/pricing 302 Country=fr
```
Redirect visitors from the United States:
```text theme={null}
/store /us/store 302 Country=us
```
### Language condition example
Redirect users who prefer Spanish based on the `Accept-Language` header:
```text theme={null}
/docs /es/docs 302 Language=es
```
Redirect users requesting German content:
```text theme={null}
/help /de/help 302 Language=de
```
Redirect rules are processed from top to bottom, and the first matching rule encountered is applied. If multiple rules target the same path, only the first one will be used, and all subsequent rules for that path will be ignored.
## Header-based conditions
You can apply redirect rules when a request only contains a specific HTTP header by adding a `Header:` condition at the end of the rule.
For example, the following rule redirects requests to the Markdown version of a page only when the client requests the `text/markdown` content type:
```text theme={null}
/quickstart/ /quickstart.md 301 Header:Accept=text/markdown
```
Header names are matched case-insensitively.
This is useful for:
* content negotiation,
* API or client-specific redirects,
* serving alternate formats,
* or applying redirects only for certain request types.
## Custom 404 page handling
You can create a custom 404 page for any path that doesn’t resolve to a static file; no redirect rules are required. Simply add a `404.html` file to your site, and it will automatically be shown whenever a path cannot be found.
You can also combine custom 404 pages with redirects by defining explicit rules for different languages or directory paths. For example:
```text theme={null}
/en/* /en/404.html 404
/de/* /de/404.html 404
```
These rules ensure that the corresponding 404 pages are displayed only for missing assets within those specific paths.
## Force redirects
In some cases, a redirect may not occur because an existing file matches the requested URL path. To override this behavior, you can force the redirect by adding an exclamation mark (`!`) to the status code.
For example:
```text theme={null}
/store/offers /store/best-offers.html 200!
```
In this example, `/store/offers` will always serve the content from `/store/best-offers.html`, even if a file such as `/store/offers/index.html` exists.
## Splats
An asterisk (`*`) represents a splat, which matches anything that follows it in a path, for example:
```text theme={null}
/resources/* /library/:splat
```
This would redirect a URL such as `/resources/guides/getting-started`\
to `/library/guides/getting-started`.
Redirect rules always apply the first matching rule, therefore, more specific rules should appear before more general ones.
The following limitations apply to splats:
* \*\*No mid-path wildcards: \*\*You cannot place an asterisk in the middle of a path—for example, `/docs/*.html` is not valid. Splats can only appear at the end of a segment.
* \*\*No exclusions within a splat rule: \*\*You cannot exclude specific paths directly within a splat redirect. To handle exceptions, create a more specific rule above the splat rule, ensuring it is matched first.
## Domain-level redirects
Redirect rules can also match a full URL, including the hostname, instead of only a path. This is useful for redirecting one domain to another when both point to the same static site. For example, to permanently redirect the www subdomain to the apex domain:
```text theme={null}
https://www.example.com/* https://example.com/:splat 301!
```
This redirects any URL on `www.example.com` to the same path on `example.com`, for example, `https://www.example.com/about` redirects to `https://example.com/about`. The forced redirect (`!`) ensures the rule applies even when the requested file exists on the site.
For the rule to take effect, both domains must be [added and pointed to your static site](/static-sites/domains).
## Placeholders
You can use placeholders in both the origin and target paths to dynamically capture and reuse parts of a URL, for example:
```text theme={null}
/store/:category/:item /products/:category/:item
```
In this example, a URL such as`/store/electronics/headphones`would redirect to `/products/electronics/headphones`.
A placeholder matches either:
* a single path segment between two slashes (`/`), or
* the final segment of a path, including any file extension but excluding the query string.
## Query parameters
You can use query parameters to create more precise redirect rules.
### Matching a single query parameter
**Example:**
```text theme={null}
/search q=:term /results/:term 301
```
This redirects a URL like `/search?q=laptops` to `/results/laptops` with a 301 redirect.
This rule matches only when the `q` parameter is present and no additional parameters are included. If the URL includes other parameters, such as `&sort=asc`, it will not match this rule.
### Matching multiple query parameters
Add each parameter as its own key/value pair, separated by a space:
```text theme={null}
/products category=:category brand=:brand /browse/:category/:brand 301
```
This matches URLs such as `/products?category=shoes&brand=nike` to `/browse/shoes/nike`
### Handling optional or multiple parameter combinations
When parameters may or may not be present, list redirects from most specific to most general so the correct rule is matched first.
**Examples:**
```text theme={null}
# Both parameters present (order from the browser does not matter)
/items/* color=:color size=:size /catalog/:color/:size/:splat 301
# Only one parameter present (must match exactly)
/items/* color=:color /catalog/:color/:splat 301
/items/* size=:size /catalog/:size/:splat 301
# Base rule when no parameters match
# If this is the only rule, all query parameters are forwarded automatically.
/items/* /catalog/:splat 301
```
This pattern ensures all variations, both parameters, one parameter, or none, are handled correctly.
## Single page applications (SPAs)
If your site is a single-page application, we strongly recommend adding a `_redirects` file to the root of your repository with the following rule:
```text theme={null}
/* /index.html 200
```
This ensures that all routes, including deep links and client-side navigation, serve your `index.html` file with a 200 status, allowing your SPA’s router to handle the actual path logic.
# Static Sites - Settings
Source: https://docs.sevalla.com/static-sites/settings
Configure settings for your static site projects.
On your static site’s **Settings** page, you can view and edit details about your site, enable or disable auto-deploy and pull request previews, update your build strategy, or delete the site.
It also shows that your site is deployed to [the Edge](/static-sites/overview#the-edge). Static sites are pushed to the Edge at 260+ CDN locations. Visitors to your site are served the closest, fastest, and easiest-to-access CDN location.
## General
This section shows the static site display name, name, and ID. To change the display name, click **Update display name**, enter a new name, and click **Update display name**.
## Deploy
### Source
This shows information about the site source, including the following about your Git repository:
* **Source type:** Shows if the repository is private or public.
* **Git type:** Shows which Git provider the site is using.
* **Repository:** The Git repository.
To change any of the details, click **Update source**.
### Auto-deploy
Use this option to automatically deploy each time a commit is made to the selected branch.
To enable or disable automatic deployments or change the branch to automatically deploy from, click **Update auto-deploy**. Select the required options and click **Update auto-deploy**.
### Deploy paths
Deploy paths allow you to trigger deployments based on a specific set of rules. You can define which file changes should initiate a deployment and which should be ignored. For example, you can trigger deployments only when files in `/src/frontend/**` are modified or skip deployments if changes are limited to `**/*.md` files. This can be especially useful for monorepos.
To configure deploy paths, click **Update deploy paths**.
To trigger a deployment when a file is changed within a specific path, select **Allow paths**. To skip a deployment when a file is changed in a specific path, select **Ignore paths**.
Add the required path patterns and click **Update deploy paths**.
### Git Large File Storage (LFS)
If your repository tracks files with [Git LFS](https://git-lfs.com/), Git LFS support ensures the actual file contents are fetched when the repository is cloned for a build. When disabled, LFS pointers are checked out as-is and the underlying objects are not downloaded.
Git LFS is enabled by default. The current state is shown as a **Git LFS enabled** or **Git LFS disabled** badge. To change it, click **Enable** (or **Disable** if it is already on), then click **Continue**. The change takes effect on the next deployment.
### Pull request previews
Pull request previews allow you to preview your site so you can review the changes before you deploy them to your site. To enable pull request previews, click **Enable previews** > **Continue**.
If you enable pull request previews, this creates a new deployment for each pull request, which will increase your build minutes and bandwidth usage.
When pull request previews are enabled, and you merge a pull request in your Git provider, Sevalla creates a **Preview** environment in your **Deployments**.
When you select the deployment, click **View previews** to view a preview of the branch or the commit.
If you enable pull request previews, you can select whether to use the [environment variables](/static-sites/environment-variables) in the production environment, preview environment, or both.
Preview deployments are automatically deleted after 30 days.
## Build
This shows information about your environment's build strategy. To change any of these settings, click **Update build strategy**, and select from the following:
* **Build site before publishing:** Choose if you want Sevalla to build your site before it's deployed or not.
* **Node version:** Optional. If you enter a build command, you can specify which major version of Node.js to use during the build process to ensure compatibility and avoid errors. When you select the major version, Sevalla pulls the latest image for that version during the build. You can also choose, `latest` to use the most up-to-date version and `lts` for the currently active long-term support version.
* **Build command:** Optional. If your static site requires a build command, enter it here.
* **Root directory**: Optional. This field defines the root folder of your static site, which is useful if you have a non-standard folder structure or [monorepo](/applications/reference/glossary#monorepo) setup.
* **Publish directory**: Optional. If this is left blank, it defaults to the root folder. If you want to publish your site to a specific directory, enter it here, relative to the repository root. If you have an HTML site that doesn’t need to be built that you want to run from a specific directory, place your site files in that directory and enter it here, relative to the repository root.
* **Index file**: If you use a single-page application (SPA), enter the site’s default page. SPAs typically use a single HTML file, commonly named `index.html`. When a user enters a URL for your site, all navigation traffic is directed through the index file to ensure seamless navigation within the site.
* **Error file**: If you use a single-page application (SPA), you can specify which file to redirect traffic to if an error occurs in the navigation.
If you change anything beyond the site name, you must manually deploy your site again (click Deploy now on the Deployments page).
## Redirects
Pretty URLs help standardize your site’s URLs and improve SEO. This feature automatically enforces a trailing slash on the path of static site requests using a 301 redirect. For example, `/about` or `/about.html` would be redirected to `/about/`
By ensuring consistent URL structure, pretty URLs prevent duplicate content issues and improve search engine indexing.
To enable pretty URLs, click **Enable pretty URLs** and then click **Continue**.
## Danger zone
Only Company Owners and Company Administrators can delete a static site. For information about how to change a user’s access, refer to User Management.
If you no longer need the static site, click **Delete static site**. To confirm the deletion, click **Continue**.
Deleting the site also completely removes all of its associated files and settings. Once it is deleted, you cannot recover a site in Sevalla.
Depending on the site's caching headers and the user’s browser settings, the deleted site may still appear to be available for a few minutes or hours due to caching.
# Static Sites - Troubleshooting
Source: https://docs.sevalla.com/static-sites/troubleshooting
Troubleshoot common static site deployment problems.
If you run into any issues with your static site, check the following for tips and solutions for common errors.
## 403 error
If the deployment of your site completes without error, but you see a 403 error when trying to visit the site in your browser, here are a few things to check:
1. If your site depends on a build step, is the **Build command** (**Settings** > **Basic details**) filled in and correct?
2. Is the **Publish directory** correct?
3. Are your file permissions correct? We generally recommend the following permissions for static sites:
* **Directories:** 755
* **Files:** 644
**File permissions control who can:**
* **Read:** See the contents of a file or view files in a directory.
* **Write:** Modify a file, or add or delete files in a directory.
* **Execute:** Run a file and/or execute it as a script, or access a directory and perform functions and commands.
Each file and directory has its own set of file permissions, shown as a 3-digit number. Each number indicates the permission level for each category (read, write, and execute) shown above.
## 404 error
If the deployment of your site completes without error, but you see a 404 error when trying to visit the site in your browser, there are a few things to check:
1. If your site depends on a build step, is the **Build command** (**Settings** > **Basic details**) filled in and correct?
2. Is the **Publish directory** correct?
3. Is your repository [compatible with Static Site Hosting](/static-sites/get-started/static-site-generators#static-site-generator-compatibility)? It should contain either:
* A static site framework that uses Node.js for the build step.
* Or static files, such as HTML, CSS, and JavaScript, that do not require a build step (leave the **Build command** blank).
The **Build command** tells our system how to assemble your site, and the **Publish directory** is the subdirectory where the finished site files live relative to the root of your repository. If your site depends on a build step, it’s crucial to fill out these fields correctly. This will ensure your site is built and served as you intend. If the **Build command** is left blank, the system may indicate the deployment is complete, but it will only upload the unbuilt contents of your repository.
## Incorrect Node version
If you [enter a build command](/static-sites/get-started/add-a-static-site) for your site, you can select the Node version to use. If you select the incorrect version, the deployment will fail, and there will be an [error in the deployment logs](/static-sites/deployments) that indicates a different Node.js version is needed, similar to this:
```
"Build project": error [[email protected]](/cdn-cgi/l/email-protection): The engine "node" is incompatible with this module. Expected version "16.14.0". Got "16.20.0"
```
Check your [static site’s settings](/static-sites/settings), change the Node version as needed, and manually deploy the site again (click **Deploy now** on the [Deployments page](/static-sites/deployments)).
## Unable to determine package manager
If an issue occurs with the [build command](/static-sites/settings) or configuration file, you may see the following error:
> Error: Unable to determine package manager
This error usually occurs due to an incorrect build command or a missing or incorrectly configured **package.json** file. Here are a couple of things to check:
1. Is the **Build command** (**Settings** > **Basic details**) filled in and correct?
2. Is the **package.json** file in your git repository?
3. Is the **package.json** file configured correctly, including any conflicting Node version? For instance, you may have chosen Node version 18.16.0 when you [added the static site](/static-sites/get-started/add-a-static-site), but in the **package.json** file, you may have set the Node version to something different, like the following example:
```json theme={null}
"engines": {
"node": ">=20.0.0"
}
```
# Contact support
Source: https://docs.sevalla.com/support/contact-support
Official Sevalla support is available via chat, which is the fastest and most reliable way to get help. Our Discord is a community space where developers connect, share ideas, and help each other.
Sevalla's support is powered by Stella, our AI support agent built on Claude, available through the chat system directly inside Sevalla. Stella is the first point of contact for all customers and can resolve most common questions and issues. Customers are initially assisted by Stella, with human support available directly to customers above a certain spending level.
Depending on the permissions granted by your company, Stella can help troubleshoot issues, answer account and billing questions, analyze screenshots, and provide guidance based on your services and repositories. If additional investigation is required, Stella can escalate the conversation to our Support team.
Customers with an active paid service can also contact our Support team through live chat from anywhere within Sevalla. Human support is currently available in English, Monday through Friday, from **08:00 to 17:00 UTC**.
If you are unable to access Sevalla, you can contact our Support team by sending an email to [support@sevalla.com](mailto:support@sevalla.com) from the email address associated with your Sevalla account.
## AI support
AI support is provided by **Stella**, Sevalla's AI support agent.
AI support can only be enabled by **Company Owners** and **Administrators**, who can also determine the level of access Stella is granted. Once enabled, Stella becomes available to all users within the company. However, Stella's capabilities are limited to the permissions configured by the Company Owner or Administrator.
Depending on the permissions assigned, Stella can:
* Troubleshoot your services and Git repositories by analyzing configuration and deployment issues and providing tailored recommendations and step-by-step guidance.
* Analyze screenshots shared during a conversation and provide support based on the information shown.
* Answer billing and account-related questions.
* Determine when human assistance is needed and escalate support requests to our Support team when additional investigation or intervention is required.
* Submit product feedback directly to the Sevalla team, helping ensure feature requests, usability concerns, and other suggestions reach the right people.
This allows organizations to benefit from AI-powered support while maintaining control over the information and actions available to the AI agent.
## Enable AI support
Company owners and administrators can configure the AI support agent in **Help** > **AI Agent**.
Before enabling the agent, you must review and accept the disclosures and consent on behalf of your company. Once you have done so, click **Continue**.
Next, configure the AI agent's permissions. You can either assign one of the predefined roles, which use the same permission sets as [Sevalla's User Management](https://docs.sevalla.com/company-settings/user-management) roles, or create a custom capability permission set.
Custom permissions allow you to grant the AI agent specific create, read, update, and delete access to individual Sevalla features and resources, giving you fine-grained control over what actions the agent can perform. You can change the permissions at any time within **Help** > **AI support**.
Once you've set the required permissions, click **Enable AI support**.
## Open a support chat
To open a new support chat or ticket, log in to [Sevalla](https://app.sevalla.com/) and click the **chat icon** in the lower right corner.
Click **Send us a message**, then choose between AI support and human support.
Let us know what type of support you need (technical, plan questions, billing questions, etc.). Type your message (you can attach files via the paper clip icon) and press enter/return (or click on the arrow) to send.
If you have a paid service but you don’t see the support icon, it might be because you have an ad blocker running. We’ve also observed that certain VPN services can interfere with the live chat feature. If you are experiencing issues with live chat, try enabling “Don’t run on pages on this domain” in your ad blocker or disabling your VPN.
### Save a chat transcript
To download a transcript of your conversation, scroll to the top of the window, click the ellipsis (three dots), and click Download transcript. A pop-up window will appear with a .txt file of your transcript that you can save to your computer.
Depending on your browser settings, the pop-up for downloading your transcript may be blocked. If it is, you’ll need to update your preferences to allow pop-ups from app.sevalla.com and click the arrow icon again.
# Scope of support
Source: https://docs.sevalla.com/support/scope-of-support
Understand what our support covers and the limits of our assistance.
Support is provided through the [chat system](/support/contact-support/#open-a-support-chat) integrated directly into Sevalla. To access support, click the chat icon in the lower-right corner of Sevalla at any time.
Sevalla offers both **AI-powered support through Stella** and **human support from our Support team**. Depending on your needs, Stella may be able to answer your question immediately or help gather information before escalating the conversation to a support engineer.
In this article, we'll explain how each support option works, what our team can assist with, and the limitations that apply.
## Getting help fast
For the fastest assistance, we recommend:
1. Asking Stella, our AI support agent.
2. Searching the Sevalla documentation.
3. Contacting our Support team through chat.
Many common questions can be answered immediately by Stella or by articles in our documentation, helping you resolve issues without waiting for a response from a support engineer.
## AI support
Sevalla includes an AI support agent called **Stella**.
AI support can only be enabled by **Company Owners** and **Administrators**, who can also control the permissions granted to Stella. Once enabled, Stella is available to all users within the company, but its capabilities are limited to the permissions configured by the Company Owner or Administrator.
Depending on the permissions assigned, Stella can:
* Troubleshoot services and Git repositories by analyzing configuration and deployment issues and providing tailored recommendations and step-by-step guidance.
* Analyze screenshots shared during a conversation and provide support based on the information shown.
* Answer billing and account-related questions.
* Help users navigate Sevalla features and documentation.
* Determine when human assistance is required and escalate conversations to our Support team when additional investigation or intervention is needed.
This allows teams to benefit from AI-powered assistance while maintaining control over what information and actions are available to the AI agent.
## Human support
Customers with an active paid service can contact our Support team through chat directly from Sevalla.
Our Support team can assist with issues including:
* Troubleshooting platform issues while creating or managing [applications](/applications/get-started/add-an-application), [static sites](/static-sites/get-started/add-a-static-site), and [databases](/databases/get-started/add-a-database).
* Problems related to Sevalla deployment features, including [Nixpacks](/applications/build-options/nixpacks), [Buildpacks](/applications/build-options/buildpacks), [environment variables](/applications/environment-variables), [processes](/applications/processes), and service [connections](/applications/networking).
* Troubleshooting issues encountered while adding or verifying domain names.
* Investigating platform and infrastructure availability.
* Resolving missing or broken [connections](/applications/networking) between Sevalla-hosted services and databases.
## If you're unsure, ask
If you're unsure whether an issue falls within our support scope, don't hesitate to start a chat. Stella or a member of our Support team can help determine the best next steps.
## Feedback and testing opportunities
Sevalla occasionally offers opportunities to test and provide feedback on new features and products.
Because beta testing often requires additional investigation and collaboration, communication may take place over several business days. As with any beta feature, these features should be used with caution and are not intended for production workloads.
## Sevalla support can’t help with development responsibilities
Sevalla provides the platform that hosts your applications, static sites, and databases. However, we do not assume responsibility for application development or ongoing development work.
For this reason, some items fall out of scope for our Support team, such as:
* Selection, installation, and configuration of applications, static sites, or databases.
* Changes to the appearance, content, or functionality of your application or static site.
* Code audits or code editing.
* Migrating your application, static site, or database to or away from Sevalla.
* Investigation of application-specific error messages or troubleshooting application performance.
* Build failures due to missing dependencies or misconfigurations.
* Troubleshooting [Dockerfile](/applications/build-options/dockerfile) misconfigurations or assisting with the creation of Dockerfiles.
* Troubleshooting common Git issues such as merge conflicts, erroneous commits, or setting up Git hooks.
* The development, processing, or handling of the Sevalla REST API in your application or site.
# Overview
Source: https://docs.sevalla.com/templates/overview
Browse available templates to jumpstart your projects.
Sevalla's one-click templates allow you to deploy an application on our platform in minutes. You can filter the templates to find specific types of applications, such as AI, CMS, or Storage applications, or search the template library for a specific application.
To use a template, simply click **Deploy now** on any of the templates, choose your [data center location](/service-information/data-center-locations/), and click **Deploy template**.
To find out more about each template, click on the template name. This shows you where the template is stored, the README, metadata showing when the template was created and how many times it has been deployed in Sevalla, and any requirements for the application, such as environment variables. During the template's deployment, you can click on the application name to open the application deployment in Sevalla.
# API Keys
Source: https://docs.sevalla.com/tools/api-keys
Learn how to add and manage your API keys in Sevalla.
[Sevalla’s REST API](https://api-docs.sevalla.com/) (Application Programming Interface) gives you a simple yet powerful way to access and interact with your Sevalla projects. It streamlines working with our platform, making it easy to retrieve data, perform actions, and automate tasks efficiently.
For full details on available API endpoints, to download our OpenAPI specification, and to try out endpoints, see our [API reference](https://api-docs.sevalla.com/).
## Authentication and user access (API key)
To use Sevalla’s API, you need to generate an API key to authenticate and access your account through the API. You can generate multiple API keys.
Generate an API key from your [Sevalla dashboard](https://app.sevalla.com/api-keys) > **Integration** > **API keys** > **Create API key**. This key authenticates all API requests.
Pass your API key as a Bearer token in the `Authorization` header:
```bash theme={null}
curl -H "Authorization: Bearer YOUR_API_KEY" \
https://api.sevalla.com/v3/applications
```
Browse the endpoint reference in the sidebar of the [API reference docs](https://api-docs.sevalla.com/). Each endpoint includes request and response schemas, parameter details, and code examples you can copy directly into your project.
Use the **Try it** console on any endpoint page to make live API calls. You'll need your API key and any required parameters for the endpoint you want to test.
When the API key is provided, **this is the only time you can see it**. Make sure you **copy it and store it somewhere safe**.
To remove an API key, click the ellipsis (three dots) and click **Delete**.
## API permissions
When creating an API key, you can choose a predefined role or define custom capabilities. **Predefined role** matches the existing roles available in [User management](https://docs.sevalla.com/company-settings/user-management#user-roles). **Custom capabilities** allow you to define precise permissions, such as create, read, update, or delete, at both the resource type and individual resource level.
For example, you can grant read-only access to specific applications or allow update access to selected sites only.
# Global Variables
Source: https://docs.sevalla.com/tools/global-variables
Learn how to add global environment variables in Sevalla for use across all applications.
In Sevalla, you can define global environment variables at the company level. These variables are available to all applications within the organization, making them ideal for shared settings such as API keys, credentials, or feature flags.
Set global environment variables within **Integration** > **Global variables**.
**Copy all** copies all environment variables, allowing you to paste them elsewhere. **Export to file** exports all the environment variables; if you only want to export certain values, select the required environment variables and then click **Export to file**.
You cannot use a `.env` file to pass environment variables to the application; you must set them in Sevalla. You can import the contents of a `.env` file when you add environment variables.
## Special characters in environment variables
In the environment variable keys, you can only use a-z, 0-9, or underscore (`_`). Environment variable values are applied literally, with the exception of parentheses, commas, and double quotes.
### Parentheses
Parentheses can cause the build or rollout process to fail, depending on when they are available during deployment. They cannot be used in environment variables.
### Commas
Unescaped [commas are interpreted as delimiters](/applications/troubleshooting/failed-deployment#environment-variables) and cannot be used in environment variables.
* For example: `write_stock,read_orders` will cause the rollout process to fail.
* To keep a comma inside a string, escape it with a backslash (`\`) like this: `write_stock\,read_orders` — which will be applied as `write_stock,read_orders`.
### Double quotes
Unescaped double quotes are either disregarded or will cause the rollout process to fail.
* For example, `"my_example_variable"` will be applied as `my_example_variable`.
* To keep double quotes around a variable, escape them with a backslash (`\`) like this: `\"my_example_var\"` — which will be applied as `"my_example_var"`.
* If double quotes are inside of a string (e.g. `my_exampl"e_text`), the [rollout process will fail](/applications/troubleshooting/failed-deployment).
* To keep double quotes inside a string, escape them with a backslash (`\`) like this: `my_examp\"le_var` — which will be applied as `my_examp"le_var`.
### Base64 encoded variables
If your environment variable is Base64 encoded and you experience issues (e.g. 500 errors in the browser, build errors, runtime errors, etc.), try wrapping the value of the variable with single quotes.
## Add global variables
If you use a Dockerfile to build your application and you want the environment variable to be available during build time, you must add ARG ENVVAR\_XY to your Dockerfile, where ENVVAR\_XY is the environment variable. For example, if your environment variable is DB\_CONNECTION\_URL you would need to add ARG DB\_CONNECTION\_URL.
To add global environment variables, click **Add environment variables**. Add the key-value pairs, select if the variables are to be available during runtime and/or the build process, and click **Add environment variables**.
You can reference another environment variable using the `${key}` format. For example, to reference an environment variable with the key `DB_PASSWORD` use `${DB_PASSWORD}`.
To add multiple environment variables, copy the keys and values using CMD + C (Mac) or CTRL + C (Windows), and in **Add global app environment variables**, press CMD + V (Mac) or CTRL + V (Windows). You can also paste the contents of a `.env` file or import the `.env` file using **Import .env**.
## Edit global variables
You can edit variable names (keys) or values on the **Global variables** page. To edit a variable, click the ellipsis (three dots) and click **Update**, make your changes, and click **Update global environment variable**.
## View global variables in your applications
If you have a global variable, it is displayed within each application's [Environment variables](https://docs.sevalla.com/applications/environment-variables).
# Registry Credentials
Source: https://docs.sevalla.com/tools/registry-credentials
Learn how to add and manage your registry credentials in Sevalla.
If you want to use a private Docker image for your application, Sevalla requires your registry credentials.
You can add as many registry credentials as required, within **Integration** > **Registry credentials** > **Create registry credential**.
Enter the credentials as follows:
* **Name:** Enter a name for the registry credentials to identify them when adding your application.
* **Registry:** Choose from one of the following:
* DockerHub
* GitHub Container Registry
* GitLab Container Registry
* **Username:** Enter your username for the registry provider.
* **Personal access token:** You must obtain this from the registry provider. For more information about how to obtain a personal access token, refer to one of the following:
* [DockerHub](https://docs.docker.com/security/access-tokens/)
* [GitHub](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
* [GitLab](https://docs.gitlab.com/user/profile/personal_access_tokens/)
Click **Create registry credential**.
Once you've added the required registry credentials, you can select the credentials you want to use within **Applications** > ***app name*** > **Settings** > **Build strategy** > **Update build strategy**.
# Webhooks
Source: https://docs.sevalla.com/tools/webhooks
Find out how to use Sevalla's webhooks.
Webhooks let you send real-time information from your application, database, or static site in Sevalla to another application whenever a specific event occurs. Unlike APIs, which require periodic requests to fetch data (also known as polling), webhooks automatically push data to the URL you specify.
When you create a webhook in Sevalla, we send requests to the configured endpoint for the events you select. Each request includes an svl-signature header containing the webhook’s secret. Secrets can be rotated within the webhook, and you can keep the old secret active to ensure a smooth, zero-downtime key rotation.
If a delivery fails, Sevalla automatically retries up to 12 times with progressively increasing intervals: 1 minute, 5 minutes, 10 minutes, 30 minutes, 1 hour, 2 hours, 4 hours, 8 hours, 16 hours, 1 day, 2 days, and 3 days.
For monitoring and debugging, you can view event delivery and response time charts for each webhook. Additionally, the Event Deliveries section allows you to inspect individual attempts, including full request and response details.
## Example application
The [Sevalla Discord webhook example](https://github.com/sevalla-templates/webhook-discord-example) listens for events sent by Sevalla (such as `APP_DEPLOY` or `STATIC_SITE_UPDATE`) and forwards them as notifications to a Discord channel using your Discord Webhook URL.
To use this example repository:
1. Fork the repository on GitHub.
2. [Add an application](https://docs.sevalla.com/applications/get-started/add-an-application) with the repository in Sevalla.
3. Create a [Discord webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks).
4. Create a webhook in Sevalla for the `APP_DEPLOY` event, using a dummy webhook URL to obtain the webhook secret.
5. Add the following [environment variables](https://docs.sevalla.com/applications/environment-variables)
```text theme={null}
SEVALLA_WEBHOOK_SECRET=
DISCORD_WEBHOOK_URL=
```
6. Deploy the application. Once deployed, click **View** and copy the URL.
7. Update the webhook endpoint with the URL from the deployed application in the format: `https://your-app.sevalla.app/webhook`
The webhook will now send notifications to your Discord channel whenever an application is deployed within your Sevalla company.
## Create a webhook
To create a webhook in Sevalla, go to **Integration** > **Webhooks** > **Create webhook**.
Complete the details as follows:
* **Endpoint:** Enter the URL you want to send the requests to.
* **Description:** Add a description for the webhook.
* **Allowed events:** You can select all events or choose the events you want to send requests for from the following:
* `APP_CREATE`
* `APP_UPDATE`
* `APP_DELETE`
* `APP_DEPLOY`
* `DATABASE_CREATE`
* `DATABASE_UPDATE`
* `DATABASE_DELETE`
* `STATIC_SITE_CREATE`
* `STATIC_SITE_UPDATE`
* `STATIC_SITE_DELETE`
* `STATIC_SITE_DEPLOY`
Click **Create webhook**.
Once the webhook is set up, you can view and update its details, monitor event deliveries and response time charts, and inspect each delivery attempt under the Event Deliveries section, including full request and response details.
## Roll the webhook secret
To rotate your webhook secret, select the webhook and click **Roll secret**.
Choose when you want the old secret to expire and click **Continue**.
## Update the webhook
To change the endpoint, description, or allowed events for the webhook, click **Update**.
Change the required information, and then click **Update webhook**.
## Event deliveries
You can inspect each request attempt within **Event deliveries**. This shows you the individual attempt details, the request that was made, and the response details.
## Disable a webhook
To disable a webhook, within the webhook **Danger zone**, click **Disable webhook** and then click **Continue**. This stops the webhook from sending events to the endpoint. You can re-enable the webhook to start sending events again at any time.
## Delete a webhook
To delete a webhook, within the webhook **Danger zone**, click **Delete webhook** and then click **Continue**. This completely removes the webhook and its data. This action cannot be undone, and the data cannot be retrieved once it has been deleted.
# Delete account
Source: https://docs.sevalla.com/user-settings/delete-account
Permanently delete your Sevalla user account and all associated data.
If you’re having trouble with your site, application, or database, or have questions about your plan, please open a new chat with our team. We’re here for you and are happy to help!
Your Sevalla user account is separate from your companies: the company holds your services, subscription, and billing, while your user account is your personal login, which can belong to one or more companies.
If you want to cancel your Sevalla subscription and remove your services, you are looking for [Delete company](/company-settings/delete-company). This page covers deleting your **user account**.
## Delete your user account with your company
If you are the **Company Owner** of a single company, you can delete your user account together with the company:
1. Follow the steps in [Delete company](/company-settings/delete-company).
2. In the confirmation step, select **Also delete my user account**.
Your company is deleted first, and then your user account and all associated data are removed. You are logged out once the deletion completes. This cannot be undone.
The **Also delete my user account** option is only shown when the company you are deleting is your only company.
## Delete your user account only
If you belong to multiple companies, or you are not a Company Owner, your user account cannot be deleted from the dashboard yet. Open a chat with our [Support Team](/support/contact-support/) to delete your user account.
If you are the Company Owner and want the company to continue without you, transfer it to another user first. Refer to [Transfer company ownership](/company-settings/overview#transfer-company-ownership).
# Logging in
Source: https://docs.sevalla.com/user-settings/logging-in
Learn how to securely log in to your account.
When you sign up or log in to Sevalla, you can choose to:
* Use a Sevalla account to log in, or
* Use [Single sign-on (SSO)](#single-sign-on-sso) via your Git provider.
If you choose to log in with your Sevalla account, [two-factor authentication](#two-factor-authentication-2fa) is required as part of the login process.
If you need to [reset your Sevalla password](#reset-your-sevalla-password) on your user account, you can start the process on the [Sevalla login page](https://app.sevalla.com/login/).
## Two-Factor Authentication (2FA)
[Sevalla](https://app.sevalla.com/) uses Two-Factor Authentication (2FA) to help protect your Sevalla account from unauthorized access, giving you enhanced security and greater peace of mind. 2FA requires an additional verification code sent to your email or available through an authentication or password manager app. This extra step ensures that even if someone gets your password, they won’t be able to log in without the code from your trusted device or account.
Every time you log in to Sevalla, you'll be prompted for a six-digit verification code either by [email](#email-authentication) or through an [authenticator app](#app-authentication). If you're using an authenticator app, open it, find the 2FA code, enter it into the **6-digit verification code** field, and click **Verify**. If you're using a password manager like 1Password, the code should be automatically placed in your clipboard so that you can paste it in after the first login page.
If you trust the device you’re using and select **Don’t ask for a code on this device**, you won’t need to enter an authentication code for 30 days, as long as you continue logging in with the same browser and IP address. After 30 days, we’ll prompt you for a code again to help keep your account secure.
### Email authentication
When you create your Sevalla account and log in for the first time, email is used as the default authentication method. A one-time verification code will be sent to your email address; simply enter this code in Sevalla and click **Verify** to continue. Each code can only be used once and is valid for 30 minutes. If a code is entered incorrectly ten times in a row, it will be reset.
If you don’t receive the email, check your spam or junk folder. After 30 seconds, you’ll have the option to click **Request a new code** to receive another one. If you're still having issues after requesting a new code, [contact our Support Team](/support/contact-support/).
If you would prefer to use an app to authenticate your login, you can enable [App authentication](#app-authentication).
### App authentication
If you want to authenticate your MyKinsta login with an app rather than email, click on your username, then click **Account**.
On the **My Account** page, within **Authenticator app**, click **Enable**.
You will then be prompted to scan a QR code with an authenticator app. If you’re using a password manager like [1Password](#how-to-add-sevalla-2fa-to-1password) or LastPass, we recommend using the built-in 2FA feature in those apps. Otherwise, you can use an app on your mobile device, such as Google Authenticator. If you have any issues scanning the QR code, you can enter the 16-digit code under the QR code.
Once you scan the QR code, your app should provide you with the 6-digit code to enter in Sevalla. When you enter the code, click **Enable authenticator app**.
#### How to add Sevalla 2FA to 1Password
If you’re already using [1Password](https://1password.com/) to manage passwords, we recommend using the [built-in two-factor authentication](https://support.1password.com/one-time-passwords/) feature to add your Sevalla 2FA.
In the 1Password app, navigate to the login profile for your Sevalla account and click **Edit**.
Next, click on the **New field** dropdown and select the **One-Time Password** option.
Next, click on the QR code icon in the newly created **One-Time Password** field to activate 1Password’s QR code scanner.
1password should identify any QR codes on your screen and shows the message **One-time password detected on screen**, click **Save**. You should now see a **one-time password** field in the 1Password login profile for your Sevalla account. To finish the 2FA setup process in Sevalla, copy the one-time password into the **Enter the 6-digit code you see in the app** field in Sevalla, and press **Verify**.
#### How to add Sevalla 2FA to Google Authenticator
Google Authenticator is a 2FA app that’s available for both iOS and Android devices. To add Sevalla 2FA to Google Authenticator, press the **+** button in the upper right corner of the Google Authenticator app and press **Scan Barcode**.
Next, use the camera on your mobile device to scan the QR code in Sevalla. After scanning the QR code, type in the six-digit code from Google Authenticator into the **Enter the 6-digit code you see in the app** field in Sevalla, and press **Verify**.
### How to recover your 2FA-Protected Sevalla account
If you have lost access to your 2FA device and cannot log in to Sevalla, our Support team can help you regain access to your account.
To recover your 2FA-protected account, follow the steps below.
* Send an email to [support@sevalla.com](mailto:support@sevalla.com) from the email address on file in your Sevalla account. If you use [sam@test.com](mailto:sam@test.com) to log in to Sevalla, send us an email from [sam@test.com](mailto:sam@test.com). In the email, let us know you’ve been locked out and need to regain access to your account.
* Our Support team will verify your email address to make sure it matches the one we have on file.
* Our Support team will ask you to provide the last 4 digits and the expiration date of the credit card we have on file for the account.
* After successfully verifying your email address and credit card details, our Support team will remove the authenticator app protection from your account. You can then log in to Sevalla and use email authentication to access your account.
## Single Sign-On (SSO)
Single Sign-On (SSO) saves you time by letting you log in with your Git service provider login without signing up separately for a Sevalla account.
### Access Sevalla with your Git provider login
1. To get started, head over to the [Sevalla Signup page](https://sevalla.com/signup/).
2. Select your Git provider (GitHub, GitLab, or Bitbucket).
3. When prompted, log in to your Git provider and connect Sevalla to your account.
4. Depending on your provider, when you are returned to the signup page, you may need to enter your email address and name to continue logging in to Sevalla.
### Link your Git service to your Sevalla account
1. Log in to [Sevalla](https://app.sevalla.com/), click on your username, then click **Account**.
2. On the **My account** page, go to the **Git login & repository access** section, on the Git service provider you want to use SSO for, click **Enable** on **Login disabled**.
3. When prompted, log in to your Git provider and connect Sevalla to your Git service account.
4. Now you can use SSO or your Sevalla email address and password to log in to Sevalla.
### Disconnect your Sevalla user from a Git provider
Log in to [Sevalla](https://app.sevalla.com/), click on your username, then click **Account**. On the **My account** page, go to the **Git login & repository access** section, and on the Git service you no longer want to use SSO for, click **Revoke** on **Login enabled**.
If you want to remove access to your repositories, on the Git service, click **Revoke** on **Repository access enabled**.
## Reset your Sevalla password
If you need to reset your Sevalla password, you can start the process on the [Sevalla login page](https://app.sevalla.com/login).
The forgot password feature works the same way for Sevalla users registered through a Git provider (Sevalla SSO) and those registered via the traditional signup method. This will only change your Sevalla password and doesn’t make any changes to your Git service provider account.
Click the **Forgot password** link on the Sevalla login page.
Enter your email address, and click **Reset password**.
Check your email for the reset password message from Sevalla with the subject “Password reset in Sevalla” (should arrive within 15 minutes or less) and follow the instructions provided.
# User settings - Overview
Source: https://docs.sevalla.com/user-settings/overview
Overview of user settings within Sevalla.
When you want to use one of our hosting services, you first need to **Sign up**. You can do this through the [Sevalla website](https://sevalla.com/signup/), or you may have been invited to a company via email and sent a link to join. You can choose to use single sign-on (SSO) and sign in via your Git provider, or you can create a Sevalla account that is not linked to a Git provider; if you choose this option, your Password must contain at least the following:
* 8 characters
* 1 special symbol
* 1 capital letter
* 1 number
Once the account is created, you can add the required hosting services. To find out more about your login options, including SSO and 2FA settings, refer to [Logging In](/user-settings/logging-in/).
You can access your user settings within your **username** > **Account**.