ZevCloud
Dashboard

Deployments

TanStack Start, Nuxt and other Nitro apps

Deploy TanStack Start, Nuxt, SolidStart and other Nitro apps as a Node.js server, with the server preset set to node-server.

TanStack Start, Nuxt, SolidStart, Analog and plain Nitro projects all build their server with Nitro. Nitro can compile the same app for many hosts, and the host it targets is called the server preset.

ZevCloud runs your app as a Node.js server, so the preset has to be node-server. A build for another host (Cloudflare Workers, Vercel, Netlify and similar) still builds successfully, but its output only exports a request handler and never starts a server. On ZevCloud it starts, exits straight away with no error in the logs, and is eventually stopped for crashing repeatedly.

Settings at a glance

SettingValue
Server presetnode-server
Build commandnpm run build (or your package manager’s equivalent)
Start commandnode .output/server/index.mjs
Port3000, read from the PORT environment variable

ZevCloud fills these in when it detects TanStack Start or Nuxt. If you set your own start command, keep it pointing at .output/server/index.mjs.

Set the server preset to node-server

Set the preset in your project’s config, commit, and redeploy. Pick the section for your framework.

TanStack Start

The config API changed between versions. Check the version of @tanstack/react-start (or @tanstack/solid-start) in your package.json and use the matching snippet.

Version 1.132 and later. Nitro is a separate Vite plugin. Set the preset on it in vite.config.ts:

// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import viteReact from '@vitejs/plugin-react'
import { nitro } from 'nitro/vite'

export default defineConfig({
  plugins: [tanstackStart(), nitro({ preset: 'node-server' }), viteReact()],
})

If your project uses the Nitro v2 plugin instead, the option is the same:

// vite.config.ts
import { nitroV2Plugin } from '@tanstack/nitro-v2-vite-plugin'

// ...
  plugins: [tanstackStart(), nitroV2Plugin({ preset: 'node-server' }), viteReact()],

If vite.config.ts has no Nitro plugin and uses @cloudflare/vite-plugin instead, the project is set up as a Cloudflare Worker. Remove that plugin, install nitro, and add nitro({ preset: 'node-server' }) as above.

Versions 1.121 to 1.131. Nitro is built into the TanStack Start plugin and the preset is its target option:

// vite.config.ts
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'

export default defineConfig({
  plugins: [tanstackStart({ target: 'node-server' })],
})

Version 1.120 and earlier (Vinxi, app.config.ts). The preset is server.preset:

// app.config.ts
import { defineConfig } from '@tanstack/react-start/config'

export default defineConfig({
  server: { preset: 'node-server' },
})

Nuxt

// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'node-server',
  },
})

Other Nitro apps

SolidStart (app.config.ts):

// app.config.ts
import { defineConfig } from '@solidjs/start/config'

export default defineConfig({
  server: { preset: 'node-server' },
})

Plain Nitro (nitro.config.ts). Nitro 2 imports from nitropack/config, Nitro 3 from nitro:

// nitro.config.ts (Nitro 2)
import { defineNitroConfig } from 'nitropack/config'

export default defineNitroConfig({
  preset: 'node-server',
})
// nitro.config.ts (Nitro 3)
import { defineConfig } from 'nitro'

export default defineConfig({
  preset: 'node-server',
})

What about the NITRO_PRESET variable?

ZevCloud builds every Node.js service with the build variable NITRO_PRESET=node-server, including services where no framework was detected. It usually appears in the Variables tab, and services created before this default get it on their next deploy if they don’t already have one. Apps that don’t use Nitro ignore it.

It fixes the common case: a TanStack Start or Nuxt project whose config falls back to Cloudflare or Vercel when nothing says otherwise. We’ve confirmed it on such a TanStack Start project: the same commit built cloudflare-module without the variable and node-server with it.

It can’t override a preset that’s hard-coded in your config, such as nitro: { preset: 'cloudflare-module' } in nuxt.config.ts, tanstackStart({ target: 'cloudflare-module' }), or nitro({ preset: 'cloudflare-module' }) on the Nitro Vite plugin. If your config names a preset, change it there to node-server.

To use a different preset on purpose, set NITRO_PRESET yourself in the Variables tab. ZevCloud never replaces a value you set.

Listen on PORT

Nitro’s node-server output reads the PORT environment variable and listens on all interfaces, which is what ZevCloud needs. ZevCloud sets PORT for you. Don’t set HOST or NITRO_HOST to 127.0.0.1 or localhost: the app would then only accept connections from inside its own container.

Check which preset a build used

Open the deployment’s build log on the Deployments tab and look for Nitro’s build line:

Building Nitro Server (preset: `node-server`, compatibility date: `2024-11-01`)

Nuxt prints Building Nuxt Nitro server (preset: ...), newer Nitro prints Building [Nitro] (preset: ...), and Vinxi prints Preparing app for node-server.... The same name is saved in .output/nitro.json after a local build.

If a build targets another host, ZevCloud marks the deployment with an amber Built for … notice before the app has a chance to crash, and the crash-loop email and dashboard name the build target if it does.

Using an AI coding assistant?

Updated at, Monday, October 26, 2026