# Using CLI

> Use the srvx CLI command to easily start a development or production server.

You can run `srvx` with your preferred runtime without installation:

<CodeGroup>

```bash [npm]
npx srvx
```

```bash [pnpm]
pnpx srvx
```

```bash [yarn]
yarn dlx srvx
```

```bash [Deno]
deno -A npm:srvx
```

```bash [Bun]
bunx --bun srvx
```

</CodeGroup>

## Usage

```sh
srvx   - Universal Server.

SERVE MODE

# srvx serve [options]
$ srvx serve --entry ./server.ts    # Start development server
$ srvx serve --prod                 # Start production  server
$ srvx serve --port=8080            # Listen on port 8080
$ srvx serve --host=localhost       # Bind to localhost only
$ srvx serve --static=./dist        # Serve static files (no entry needed)
$ srvx serve --import=jiti/register # Enable [jiti](https://github.com/unjs/jiti) loader
$ srvx serve --tls --cert=cert.pem --key=key.pem  # Enable TLS (HTTPS/HTTP2)

FETCH MODE

# srvx fetch|curl [options] [url]
$ srvx fetch                  # Fetch from default entry
$ srvx fetch /api/users       # Fetch a specific URL/path
$ srvx fetch --entry ./server.ts /api/users # Fetch using a specific entry
$ srvx fetch -X POST /api/users # POST request
$ srvx fetch -H "Content-Type: application/json" /api # With headers
$ srvx fetch -d '{"name":"foo"}' /api # With request body
$ srvx fetch -v /api/users    # Verbose output (show headers)
$ echo '{"name":"foo"}' | srvx fetch -d @- /api # Body from stdin

COMMON OPTIONS

  --entry <file>           Server entry file to use
  --dir <dir>              Working directory for resolving entry file
  -h, --help               Show this help message
  --version                Show server and runtime versions

SERVE OPTIONS

  -p, --port <port>        Port to listen on (default: 3000)
  --host, --hostname <host>  Host to bind to (default: all interfaces)
  -s, --static <dir>       Serve static files from the specified directory (default: public)
  --prod                   Run in production mode (no watch, no debug)
  --import <loader>        ES module to preload
  --tls                    Enable TLS (HTTPS/HTTP2)
  --cert <file>            TLS certificate file
  --key  <file>            TLS private key file

FETCH OPTIONS

  -X, --method <method>    HTTP method (default: GET, or POST if body is provided; --request is a curl alias)
  -H, --header <header>    Add header (format: "Name: Value", can be used multiple times)
  -d, --data <data>        Request body (use @- for stdin, @file for file)
  --host <host>            Host for a schemeless URL/path (default: localhost)
  --tls                    Use https for a schemeless URL/path
  -v, --verbose            Show request and response headers

  Exits with code 22 on a non-2xx response (like curl --fail).

ENVIRONMENT

  PORT                     Default port to listen on
  HOST                     Default host to bind to
  NODE_ENV                 Set to production for production mode.
```

## Port and host precedence

The port and host are resolved with the following precedence (highest first):

<steps level="4">

#### CLI flag (`--port` / `--host` / `--hostname`)

#### Module option (`port` / `hostname` exported from your server entry)

#### Environment variable (`PORT` / `HOST`)

#### Default (`3000` / all interfaces)

</steps>

## Exit codes

In **fetch mode**, `srvx fetch` exits with code **22** for any non-2xx response, and `0` for a 2xx response.

<important>

This diverges from `curl`, which exits `0` regardless of the HTTP status unless you pass `--fail`. With `srvx fetch` the non-2xx exit is the **default**, so no extra flag is needed to make a failing request fail your script.

</important>

## Runtime notes

<note>

The `--import` flag preloads an ES module (e.g. a loader like `jiti/register`). It is applied on **Node.js and Bun only** — on **Deno** it is silently ignored, since Deno does not support Node's `--import` preload flag.

</note>

## Serving static files

The CLI can serve a directory of static files, similar to [`serve`](https://github.com/vercel/serve). No server entry is required — point `--static` at any folder:

```bash
npx srvx --static ./dist
```

If `--static` is omitted, srvx serves files from a `public/` directory when one exists. When both a server entry and a static directory are present, static files take priority and unmatched requests fall through to your handler.

Static serving includes automatic `index.html` resolution, `.html` extension fallback (e.g. `/about` → `about.html`), common MIME types, gzip/Brotli compression, and path-traversal protection.

<note>

`srvx/static` is **Node-API-only** — it uses `node:fs` and `node:zlib` internally, so despite the runtime-neutral name it only works on runtimes with Node.js compatibility (Node, Deno, Bun).

</note>

For programmatic usage, import the [`serveStatic`](https://github.com/h3js/srvx/blob/main/src/static.ts) middleware:

```ts [server.ts]
import { serve } from "srvx";
import { serveStatic } from "srvx/static";

serve({
  middleware: [serveStatic({ dir: "public" })],
  fetch: () => new Response("Not found", { status: 404 }),
});
```
