CommunityCoding & Developmentgithub.com

sevalla-hosting/skills

Deploy a Next.js application to Sevalla (Kinsta's PaaS) correctly on the first try, using the Sevalla MCP server, the sevalla CLI or the Sevalla API. Use this whenever the user wants to deploy, host, ship, or "go live" with a Next.js app on Sevalla, is debugging a failed or broken Sevalla deployment of a Next.js app, is choosing between Sevalla Application Hosting and Static Site Hosting for Next.js, or is configuring build settings (Nixpacks, Railpack, Dockerfile), environment variables, ports, a database, object storage or persistent storage for a Next.js app on Sevalla. Trigger even if the user just says "deploy this to Sevalla" and the repo is a Next.js project, or if they mention sevalla.app, Nixpacks, Railpack, or Sevalla build or runtime errors alongside a Next.js codebase.

What is skills?

skills is a Claude Code agent skill that deploy a Next.js application to Sevalla (Kinsta's PaaS) correctly on the first try, using the Sevalla MCP server, the sevalla CLI or the Sevalla API. Use this whenever the user wants to deploy, host, ship, or "go live" with a Next.js app on Sevalla, is debugging a failed or broken Sevalla deployment of a Next.js app, is choosing between Sevalla Application Hosting and Static Site Hosting for Next.js, or is configuring build settings (Nixpacks, Railpack, Dockerfile), environment variables, ports, a database, object storage or persistent storage for a Next.js app on Sevalla. Trigger even if the user just says "deploy this to Sevalla" and the repo is a Next.js project, or if they mention sevalla.app, Nixpacks, Railpack, or Sevalla build or runtime errors alongside a Next.js codebase.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/sevalla-hosting/skills/tree/HEAD/skills/sevalla-nextjs-deploy

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Deploying Next.js to Sevalla

Sevalla is a PaaS (by Kinsta) with two hosting products for Next.js:

  • Application Hosting runs a real Node.js server. Required for SSR, route handlers (API routes), proxy (formerly middleware), ISR (revalidate), server actions, or websockets.
  • Static Site Hosting serves the output of a static export (output: 'export'). No server-side code at all. Limit of 100 static sites per company.

Get this decision right first. It determines everything below.

Step 0: Decide which hosting product to use

Inspect the repo before you do anything else:

  1. Read next.config.js / next.config.ts / next.config.mjs for output: 'export' or output: 'standalone'.
  2. Search the codebase for: app/api/, pages/api/, proxy.ts or proxy.js (Next.js 16), middleware.ts or middleware.js (Next.js 15 and earlier), "use server", getServerSideProps, revalidate (ISR), NextResponse, or any database or auth client used server-side.
  3. Decide:
    • Any of the above present: Application Hosting (server required). Go to Step 1.
    • None present, purely static content, marketing or blog: Static Site Hosting is simpler and cheaper. Read references/static-hosting.md.
    • Unsure, or the user wants dynamic features later: default to Application Hosting. It can do everything static hosting can.

If it is genuinely ambiguous, ask the user one question: "Does this app need a live server (API routes, ISR, auth, database calls) or is it fully static content?" Do not guess silently, because the wrong choice means redoing the whole deployment.

Also check the repo for a database client (Prisma, Drizzle, pg, mysql2, Mongoose, redis, ioredis) and for file uploads. If you find one, read references/data-services.md before Step 3.

Step 1: Choose a build strategy (Application Hosting)

Sevalla builds Git-based applications with one of four strategies:

  • Nixpacks, the default. Zero config for a standard Next.js app. Use it unless there is a reason not to.
  • Railpack, the successor to Nixpacks. Also zero config. A good choice for a new app. Set it with the API field build_type: "railpack".
  • Dockerfile, when the user wants a small, reproducible image, has a monorepo that the auto-detected builders struggle with, or asks for Docker.
  • Buildpacks (pack). Rarely needed for Next.js.

Read references/app-hosting.md before you write any config. It has the exact package.json scripts, the recommended Dockerfile, nixpacks.toml overrides and the monorepo Build path setting. Do not hand-roll a Dockerfile or nixpacks.toml from general Next.js knowledge. Sevalla has specific constraints (below) that generic guides do not mention.

Step 2: Prepare the repo (Sevalla constraints)

These trip up almost every first deployment. Check all of them before you deploy:

  1. Read the port from $PORT and bind to 0.0.0.0. The default web-process port is 8080, and Sevalla passes it in PORT. Only ports 80 and 443 are open to the internet, and Sevalla routes them to $PORT. With Nixpacks or Railpack, the start script must be next start -p ${PORT:-8080} -H 0.0.0.0. Plain next start listens on 3000.
  2. NEXT_PUBLIC_* variables are inlined at build time. Create them as build-time variables (is_buildtime: true) before the build runs. A variable added later needs a new deployment, not a restart.
  3. The filesystem is ephemeral. Anything the app writes to disk at runtime (uploads, generated files, on-disk caches) is lost on every redeploy or restart. Use object storage, or a persistent disk if the app truly needs local disk writes (for example SQLite or a self-hosted CMS). See references/data-services.md.
  4. output: 'standalone' only with the Dockerfile. next start does not use the standalone bundle, and Next.js warns "next start" does not work with "output: standalone" configuration. So with Nixpacks or Railpack, leave output unset. With the Dockerfile, set output: 'standalone'.
  5. Do not commit node_modules or .next. A committed node_modules folder is a documented cause of failed builds on Sevalla.
  6. Pin the Node.js version. Nixpacks uses Node 18 by default, and Next.js 16 needs Node 20.9 or later. Set "engines": { "node": "22.x" } in package.json, or the build-time variable NIXPACKS_NODE_VERSION=22.
  7. Monorepos: set the Build path (API field build_path) to the Next.js app's folder, for example apps/web. With the Dockerfile, also set docker_context and dockerfile_path.
  8. package.json name: do not use "node" or "js" as the package name. It is documented to break Sevalla builds.
  9. Double quotes in variable values must be escaped as \". Unescaped quotes are dropped or make the rollout fail.
  10. Secrets (database URLs, API keys) go into Sevalla environment variables. Never commit a .env file with real secrets.

Step 3: Deploy

Use the first option that is available, in this order:

  1. The Sevalla MCP server (https://mcp.sevalla.com/mcp). It has two tools: search finds API endpoints in the spec, and execute runs JavaScript that calls sevalla.request({ method, path, body }). Use the API paths in the table below.
  2. The sevalla CLI, with --json on every command so you can read the IDs. Install with npm install -g @sevalla/cli (Node 22+) or brew install sevalla-hosting/tap/sevalla. Log in with sevalla login (device authorization in the browser) or set SEVALLA_API_TOKEN.
  3. The REST API at https://api.sevalla.com/v3 with a bearer API key.

If none is available, tell the user how to add the MCP server (see the coding-agent quick-starts at https://docs.sevalla.com/quick-starts/coding-agents/overview), or give them the dashboard steps in references/dashboard.md. Only the first login needs the user.

Application Hosting

#ActionAPI (MCP execute or REST)CLI
1Pick a locationGET /resources/clusterssevalla resources clusters --json
2Create the appPOST /applications with display_name, cluster_id, source (privateGit for a connected GitHub, GitLab or Bitbucket repo, publicGit for a public URL), git_type, repo_url, default_branchsevalla apps create --name <name> --cluster <cluster-id> --source privateGit --git-type github --repository https://github.com/<owner>/<repo> --branch <branch> --json
3Set the build strategy and build path, if not the defaultsPATCH /applications/{id} with build_type (nixpacks, railpack, dockerfile, pack) and build_pathsevalla apps update <app-id> --build-type railpack --json. The CLI has no build-path flag: sevalla apps update <app-id> --data '{"build_path":"apps/web"}' --json
4Add environment variablesPOST /applications/{id}/env-vars with key and value. is_runtime and is_buildtime both default to true, which is right for NEXT_PUBLIC_*.sevalla apps env-vars create <app-id> --key <KEY> --value "<value>" (available at build time and at runtime)
5Connect a database, if anySee references/data-services.md
6DeployPOST /applications/{id}/deployments. Creating an app does not start a deployment.sevalla apps deployments trigger <app-id> --branch <branch> --json

If step 2 fails with HTTP 500 for a privateGit repo, the most likely cause is that Sevalla's GitHub app cannot see the repository. The API does not say so. Check with sevalla git providers --json: the settings_url opens the GitHub app installation. The user (or an owner of the GitHub organization) must give the app access to the repository. A repo in an organization the user does not own needs an owner to add it. Then try step 2 again.

A new app has auto deploy turned off. If the user wants a deploy on every push, set auto_deploy: true with PATCH /applications/{id} (works for privateGit only).

For Static Site Hosting, follow references/static-hosting.md instead. Creating a static site starts its first deployment automatically.

Step 4: Verify

A deployment that started is not a deployment that works. Do all of these before you tell the user it is done:

  1. Wait for the build. Poll GET /applications/{id}/deployments/{deployment_id} (CLI: sevalla apps deployments get <deployment-id> --app-id <app-id> --json) every 15 to 30 seconds until status is success or failed. Other values are waiting, inProgress, cancelled and skipped.
  2. If it failed, read the build log. GET /applications/{id}/deployments/{deployment_id}/logs (CLI: sevalla apps deployments logs ...). Match the error against the troubleshooting table in references/app-hosting.md, fix the cause, and deploy again. Do not guess twice without reading the log. Judge success by the deployment status, not by log severity: normal build output written to stderr shows up with "severity": "error" in a successful build.
  3. Find the live URL. GET /applications/{id}/domains (CLI: sevalla apps domains list --app-id <app-id> --json). Every app gets a free *.sevalla.app domain after its first successful deployment.
  4. Request the URL. Expect HTTP 200 on / and on one route handler, if the app has one. A 502 or a timeout usually means the server is not listening on $PORT and 0.0.0.0.
  5. If the app answers with an error, read the runtime log. GET /applications/{id}/runtime-logs (CLI: sevalla apps logs runtime <app-id>).

Then tell the user the live URL, what you configured, and anything they must do themselves (for example, add DNS records for a custom domain).

Step 5: Optional next steps

  • Custom domain: sevalla apps domains add <app-id> --name example.com. The user must add the DNS records that Sevalla returns. SSL is included.
  • Scaling: sevalla apps processes update <process-id> --app-id <app-id> --instances <n>. With more than one instance, do not use a persistent disk for shared state. Use object storage or a database.
  • Rollback: sevalla apps deployments rollback <app-id> --deployment-id <id>.

Reference files

  • references/app-hosting.md: package.json scripts, Nixpacks and Railpack notes, the recommended Dockerfile, monorepo setup, troubleshooting table.
  • references/static-hosting.md: static export setup and deploy for Static Site Hosting.
  • references/data-services.md: databases, object storage and persistent disks, and how their connection details reach the app.
  • references/dashboard.md: the same steps in the Sevalla dashboard, for a person.

Related Skills