> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waniwani.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy

> Deploying a kit app is a git push. Vercel needs a four-line vercel.json, Docker and Alpic read their config from the build, and secrets come from the app's .env or the platform.

`waniwani init` asks where the app deploys, because the answer decides the one config file the repo carries:

```text theme={null}
◆  Where will this deploy?
│  ● Vercel (git push, or `vercel deploy --prebuilt`)
│  ○ Docker
│  ○ Alpic
│  ○ I don't know yet
│  ↑/↓ to navigate • Enter: confirm
└
```

Pass `--host vercel`, `--host container`, `--host alpic` or `--host none` to answer ahead of time.

## Vercel

Only Vercel leaves anything behind, and it is four lines:

```json vercel.json theme={null}
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "framework": null
}
```

`framework: null` selects the `Other` preset. That one key is the only thing a repo cannot say any other way: the preset is a project setting Vercel resolves *before* the build command runs, so a project whose dashboard says `Next.js` or `Express` fails on the preset and never reaches the build. `Other` is what runs the `build` script and adopts what the build produced.

```text theme={null}
Error: No Next.js version detected.
```

Nothing else belongs in that file. `waniwani build` writes a Build Output tree inside `.waniwani/` (the bundled function, the static assets, the routing config) and the build's last step moves it to `.vercel/output` at the app root, the one path where Vercel adopts one. A `buildCommand` would restate the `build` script that already runs, and a `routes` table would duplicate routing the build writes. Both go stale against a kit that moved on; `framework: null` is a fact about the project, so it never changes.

```bash theme={null}
git push                          # a git-connected project builds and serves it
vercel deploy --prebuilt          # or upload the tree a local build produced
```

A prebuilt deploy skips the preset question entirely, since it uploads the tree and asks Vercel to build nothing.

<Accordion title="Why the build routes /api/* itself">
  One thing the kit decides on the app's behalf, in that tree's own routing table:

  ```json theme={null}
  { "src": "/api(/.*)?", "dest": "/mcp" }
  ```

  Vercel reserves a root `api/` directory. It compiles every file under one into a serverless function of its own, and an endpoint module is not a Vercel handler, since `defineEndpoint({ ... })` is an object. The reservation cannot be waived, because the file list is read before the build command runs:

  ```text theme={null}
  Error: File not found: /vercel/path0/api/cal/book.ts
  ```

  So the route goes in ahead of the tree's `filesystem` handler, which is the phase those functions sit in. `/api/*` reaches the server the kit built, and the ones Vercel made are never routed to. They still cost build time, two dead functions per app.
</Accordion>

<Warning>
  An app carrying a `vercel.json` from an earlier setup has to lose everything in it but `framework`. A `buildCommand` that stages the tree by hand deletes what the build just placed. `waniwani check` names the keys that fight the build.
</Warning>

## Docker

The build writes a `Dockerfile` and `.dockerignore` into `.waniwani/`, so the image is built from there:

```bash theme={null}
waniwani build
docker build .waniwani
```

## Alpic

`alpic.json` also comes out of the build:

```bash theme={null}
waniwani build
cd .waniwani && alpic deploy
```

## Secrets and environment variables

`.env` and `.env.local` sit next to `waniwani.config.ts`, and every command reads them before it runs anything. A variable already exported in the shell or set by CI wins over both files, and a hosted deploy sets its variables on the platform and reads no file at all.

```bash .env theme={null}
# Optional. Without it the app still runs: flows use MemoryKvStore and
# withWaniwani degrades to a no-op. With it, flow state is hosted and tracking
# reaches app.waniwani.ai.
WANIWANI_API_KEY=
```

Loading them this early is what lets a module build its client at import time:

```ts lib/waniwani.ts theme={null}
export const wani = waniwani({ apiKey: process.env.WANIWANI_API_KEY });
```

The generated project runs from `.waniwani/`, one level below the file, and a module's imports are evaluated before any line of the module that pulled it in, so neither `dotenv/config` nor a load inside generated code arrives in time. `waniwani check` reads the same files for the same reason.

On a hosted deploy, environment variables live on the platform. A Vercel project that sets its variables for production alone gets previews with none, which for an app whose flow reads `WANIWANI_API_KEY` at import time means a function that fails to boot. Set them for every environment the project serves.

Get an API key from the [Waniwani dashboard](/sdk/configuration/api-key). What the key turns on is described under [Waniwani Platform](/sdk/platform/overview).
