# Development server

> Serve a directory with page reload using `elide dev` or `elide serve`, run a Fetch-style handler, and run a server across several Elide contexts.

`elide dev` and `elide serve` serve a directory of files or run a server script.

```bash
elide dev ./public
elide serve ./dist
```

| Command | Default address | Reload on file change |
| --- | --- | --- |
| `elide dev` | `127.0.0.1:3000` | HTML pages, when serving a directory |
| `elide serve` | `127.0.0.1:8080` | No |

A directory starts a file server; a script runs as a program and is not reloaded.

<img src="https://elide.help/assets/demos/dev-server.gif" alt="Starting the development server and observing a changed page" width="1591" height="691" loading="lazy" decoding="async" class="rounded-lg border border-border my-6 w-full" />

| Flag | Effect |
| --- | --- |
| `--host HOST` | Bind host. |
| `--port PORT` | Bind port. |
| `--no-tui` | Plain log output instead of the TUI. |
| `--no-watch` | `dev` only: no watching or reload. |
| `--contexts=N` | Run `N` copies of the app; `auto` sizes from the CPU cores. Linux only. |

## Serve a directory

| Request | Response |
| --- | --- |
| `/`, `/docs`, `/docs/` | The directory's `index.html` |
| A directory without `index.html` | `404`; there are no directory listings |
| `/about` when only `about.html` exists | `404`; link to `about.html` |
| A dot file such as `/.env` | `404`. `/.well-known/` is served. |
| A symbolic link that points outside the directory, or `..` in the path | `404` |
| `POST` and other methods | `405` from `elide serve`; `elide dev` answers as for `GET` |

- `Content-Type` comes from the file extension: `text/html; charset=utf-8`, `text/css`, `text/javascript`,
  `application/json`, `application/wasm`, `image/png` and so on.
- Files are sent whole, uncompressed, with no `ETag`, `Last-Modified` or `Cache-Control`; `Range` and conditional
  requests get a full `200`. Put a CDN or reverse proxy in front for caching and compression.
- `elide dev` adds a reload script to each HTML page and reloads it when any file in the directory changes.

## Run a fetch handler

```js
// entrypoint.mjs
export default {
  async fetch(request) {
    return new Response("ok");
  },
};
```

```bash
elide serve entrypoint.mjs
```

`elide run entrypoint.mjs` also serves, on the exported `hostname` and `port` or `127.0.0.1:8080`.
`Elide.serve({ port: 3005, fetch })` uses its own address with every command.

## Serve with several contexts

```bash
elide serve --contexts=4 entrypoint.mjs
```

- Each context runs the entry module once and keeps its own globals, so a request counter counts per context.
- A connection stays on one context for its lifetime, including keep-alive requests.
- If one context fails, the server stops.

Set `engine.contexts` in `elide.pkl` for finer control; see [Engine contexts](https://elide.help/docs/elide-pkl-reference#engine-contexts).

## Samples

- [Multi-context server](https://elide.help/docs/code-samples#multi-context-server)
