Amba

Local Dev Server

Run an Amba function locally with `amba functions dev <file>` — hot reload, .env.local pass-through, and the same bundler your production deploy uses.

amba functions dev <file> spins up a local HTTP server that runs your function exactly the way the production runtime would. Save the file and the server rebuilds and reloads — you don't have to restart it.

Quick start

amba functions dev ./functions/hello.ts
✓ Bundled in 124 ms (24 KB)
Listening on http://127.0.0.1:8787
Watching ./functions/hello.ts — save to reload.

Hit the endpoint:

curl 'http://127.0.0.1:8787/?name=amba'
{"greeting":"hello, amba"}

Edit the handler, save, and the next request runs the new code.

What it does

  • Same bundler as production. amba functions dev uses the same build pipeline as amba functions deploy — externalization rules, size cap, source maps. Dev → prod parity is automatic.
  • Bound to loopback. The dev server only listens on 127.0.0.1 so another device on your Wi-Fi can't reach your handler or read your .env.local.
  • Hot reload. A file save triggers a rebundle + child-process swap. In-flight requests during the swap queue at the TCP listen backlog and complete against the new bundle.
  • .env.local pass-through. Variables from your project's .env.local are injected into the child process so the handler can read them via process.env.MY_KEY. CLI-side env wins on conflict (MY_KEY=x amba functions dev ./fn.ts overrides the file).
  • Standard Request / Response. The handler signature is async (req: Request) => Response. fetch, URL, Headers, crypto, TextEncoder and friends are all available.

Flags

  • --port <n> — port to listen on (default 8787).
  • --no-watch — disable file-change hot reload. Useful when you want a stable binding (for example, when piping requests from another process that opens long-lived connections).
amba functions dev ./functions/hello.ts --port 4000
amba functions dev ./functions/hello.ts --no-watch

Handler example with .env.local secret

// functions/echo-secret.ts
export default async function (req: Request): Promise<Response> {
  const token = process.env.ECHO_TOKEN;
  if (!token) return new Response('missing ECHO_TOKEN', { status: 500 });
 
  const auth = req.headers.get('authorization');
  if (auth !== `Bearer ${token}`) return new Response('unauthorized', { status: 401 });
 
  return new Response(JSON.stringify({ ok: true }), {
    headers: { 'content-type': 'application/json' },
  });
}

.env.local in the same directory:

ECHO_TOKEN=local-dev-token

Run:

amba functions dev ./functions/echo-secret.ts
curl -H 'authorization: Bearer local-dev-token' http://127.0.0.1:8787/
{"ok":true}

The same code, deployed via amba functions deploy, reads its secret from amba secrets set ECHO_TOKEN <prod-value> — see deploy.

Common pitfalls

  • Port already in use — pass --port <free-port> or kill the existing process. The dev server bails fast rather than picking a random port (so its address never moves under you while you debug).
  • No reload after save — confirm you didn't pass --no-watch. Some editors save via "rename + replace" which a few filesystems don't notify on; touch the file (touch ./functions/hello.ts) to force a rebuild.
  • process.env.X undefined — confirm X is in your .env.local and that the variable wasn't accidentally set in your parent shell to an empty string. Parent env wins.

Next

On this page