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

# Dev server

> Local iteration with forst dev — HTTP contract, endpoints, and ftconfig.

**`forst dev`** watches your `.ft` tree, recompiles on change, and exposes a stable HTTP contract for tooling and Node clients. To call Forst from Node (including **`@forst/sidecar`** spawn/connect), see [Call Forst from Node](/docs/interop/node/call-forst).

## Start the server

The dev server watches your `.ft` tree, recompiles on change, and listens for invoke requests:

```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
npx forst dev -root ./my-service -port 8080 -config ./ftconfig.json
```

## Endpoints

| Method | Path         | Description                                |
| ------ | ------------ | ------------------------------------------ |
| `GET`  | `/health`    | Server liveness                            |
| `GET`  | `/functions` | List invokable functions                   |
| `POST` | `/invoke`    | Execute a function with JSON payload       |
| `GET`  | `/types`     | Type information for tooling               |
| `GET`  | `/version`   | Compiler version and **`contractVersion`** |

The invoke envelope uses JSON request/response bodies. The same contract applies to the built-in HTTP server in a compiled binary. See [Call Forst from Node](/docs/interop/node/call-forst).

Clients should check **`contractVersion`** on `/version` when upgrading the compiler or Node packages.

## Configuration

Share discovery rules with **`forst generate`** via **`ftconfig.json`**:

```json theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/languages/forst.json"]}}
{
  "server": {
    "port": "8080",
    "cors": true
  },
  "dev": {
    "logLevel": "info",
    "watch": false,
    "hotReload": true
  },
  "files": {
    "include": ["**/*.ft"],
    "exclude": ["**/node_modules/**", "**/client/**"]
  }
}
```

### Runtime profile (embedded / host mode)

When `server.embedded` or `node.hostMode` is true, `forst dev` compiles and runs your entry `.ft` (same pipeline as `forst run`) instead of the per-invoke HTTP executor on `:6320`.

By default, `dev.hotReload` is **true** in `ftconfig.json`, so the CLI watches `.ft` files under `-root`, recompiles on change, and restarts the generated program. Set `"dev": { "hotReload": false, "watch": false }` for a one-shot compile+run (no file watching).

Compile errors during reload are printed to **stderr** (`log.Error` + a one-line warning). The watch loop keeps running; if a previous build was already running, it stays up until a successful recompile replaces it.

`@forst/sidecar` spawn mode is an alternative: it restarts the whole `forst dev` child on `.ft` changes. You do not need the sidecar for native CLI watch in runtime profile.

## When to use dev vs pure Go

| Scenario                             | Approach                                                                                          |
| ------------------------------------ | ------------------------------------------------------------------------------------------------- |
| New greenfield service               | Compile to Go, deploy directly                                                                    |
| Local iteration from Node or scripts | **`forst dev`** on **`8080`**                                                                     |
| Production Node → Forst              | Built-in HTTP server + **`@forst/client`** — see [Call Forst from Node](/docs/interop/node/call-forst) |
| Full stack type sync                 | **`forst generate`** in CI                                                                        |

## Caveats

**`forst dev`** is **experimental**. Pin compiler versions. Run integration tests in your pipeline.

### Same port convention

**`forst dev`** defaults to **`8080`**. The built-in server in a compiled binary defaults to **`8081`**. Point **`FORST_BASE_URL`** at the server you actually run. See [Call Forst from Node § Caveats](/docs/interop/node/call-forst#caveats).

### Providers in Go host

Invoke carries request payloads only. Wire **`with`** blocks in Go before exposing handlers. See [Providers § Caveats](/docs/language/providers#caveats).

## Examples

* Repository invoke example: [`examples/in/rfc/embedded-invoke`](https://github.com/forst-lang/forst/tree/main/examples/in/rfc/embedded-invoke) (`task example:embedded-invoke:run`)
* Client integration: [`examples/client-integration/`](https://github.com/forst-lang/forst/tree/main/examples/client-integration)

## Related

<CardGroup cols={2}>
  <Card title="Call Forst from Node" icon="https://mintcdn.com/forst/r5GJChnfkgCSJa-b/icons/typescript.svg?fit=max&auto=format&n=r5GJChnfkgCSJa-b&q=85&s=8a8c0cd7b4bf60c264d51f66d0f52e91" href="/docs/interop/node/call-forst" width="512" height="512" data-path="icons/typescript.svg">
    Generated client, `@forst/sidecar`, and built-in HTTP server.
  </Card>

  <Card title="CLI reference" icon="terminal" href="/docs/workflow/cli">
    `forst dev` and other subcommands.
  </Card>

  <Card title="Generate client types" icon="https://mintcdn.com/forst/r5GJChnfkgCSJa-b/icons/typescript.svg?fit=max&auto=format&n=r5GJChnfkgCSJa-b&q=85&s=8a8c0cd7b4bf60c264d51f66d0f52e91" href="/docs/interop/node/generate-types" width="512" height="512" data-path="icons/typescript.svg">
    Emit `.d.ts` from the same sources.
  </Card>
</CardGroup>
