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 with the same export shape and env-binding contract as the
production runtime. Save the file and the server rebuilds and reloads —
you don't have to restart it.
Quick start
Hit the endpoint:
Edit the handler, save, and the next request runs the new code.
What it does
- Same bundler as production.
amba functions devuses the same build pipeline asamba 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.1so another device on your Wi-Fi can't reach your handler or read your.env.local. - Local callers only. The server answers requests addressed to
localhost,*.localhostor an IP address (127.0.0.1,[::1], an Android emulator's10.0.2.2), and a browser request only from a local page (http://localhost:<port>,http://127.0.0.1:<port>,http://0.0.0.0:<port>) or the address it called. A browser request that the browser marks as coming from another site is refused too, even a plain link or image. Anything else gets403, so a website open in your browser can't drive your function or read what it returns (DNS rebinding). Requests from curl, native apps and server code are answered. A page served from your LAN address (Expo web athttp://192.168.1.20:8081) or a tunnel's public name needs--allow-hostwith that address or name. Browsers countlocalhostand127.0.0.1as different sites: a page onhttp://localhost:3000mayfetchhttp://127.0.0.1:8787, but an image, script or link from it to that address is refused, so use the same host name in both. - 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.localas env bindings. Variables from your project's.env.localare injected asenv.*values — the same parameter the handler receives as its second argument (fetch(req, env, ctx)). CLI invocation overrides win on conflict (MY_KEY=x amba functions dev ./fn.tsoverrides the file).- Modules export shape. The handler must use
export default { async fetch(req, env, ctx) { ... } }— the same shape production requires.fetch,URL,Headers,crypto,TextEncoderand friends are all available.
Flags
--port <n>— port to listen on (default8787).--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).--allow-host <hosts>— also answer these host names or IP addresses, comma-separated, asHostand as a page'sOrigin. Use it for a tunnel that keeps its public name inHost(for example to receive webhooks through ngrok; quick tunnels get a new name each run, so pass the new one) or for a page served from your LAN address.
Handler example with .env.local secret
.env.local in the same directory:
Run:
The same code, deployed via amba functions deploy, reads its secret
from the binding the runtime injects — set the production value with
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. env.Xis undefined — confirmXis in your.env.localand that the variable wasn't accidentally set in your parent shell to an empty string. Parent env wins over.env.local.
Next
- Deploy a function — ship the handler you just iterated on.
- CLI reference — all
amba functionssubcommands and flags.