# Deno

The Deno adapter wraps `Deno.serve`: the stable, modern entry point that replaced the old `Deno.serveHttp`. Graceful shutdown uses an `AbortController`, which is the pattern Deno itself recommends.

**Diagram: Deno adapter stack**

- **Your DaloyJS App** - routes · hooks · handlers
- **Deno adapter** - serve(app) wraps Deno.serve - [signal, onListen, cert/key]
- **Deno runtime** - stable Deno.serve, TS built in

serve() drives the stable Deno.serve and threads an AbortController signal through for graceful shutdown. The same src/server.ts runs locally and on Deno Deploy.

## When to choose Deno

- You want a web-standard runtime with TypeScript built in and no transpile step.
- You deploy to Deno Deploy, or to a container running the official Deno image.
- You like Deno's permissions model and don't need the full npm ecosystem.

## Scaffold

The `deno-basic` template ships a Deno-native server with a `deno.json` import map, watch-mode dev, and `deno test`.

```bash
pnpm create daloy@latest my-api --template deno-basic
cd my-api
deno task dev    # deno run --allow-net --allow-env --allow-read --watch
```

## Install

`@daloyjs/core` is published to npm. Deno can consume it directly via the `npm:` specifier. This is the same pattern used by the official `deno-basic` scaffolder template.

```jsonc
// deno.json
{
  "imports": {
    "@daloyjs/core":  "npm:@daloyjs/core@latest",
    "@daloyjs/core/": "npm:@daloyjs/core@latest/",
    "zod":            "npm:zod@^4.4.3"
  }
}
```

## Minimal server

```ts
// src/server.ts
import { serve } from "@daloyjs/core/deno";
import { app } from "./app.ts";

const ac = new AbortController();

serve(app, {
  port: 3000,
  hostname: "0.0.0.0",
  signal: ac.signal,
  onListen: ({ hostname, port }) =>
    console.log(`listening on http://${hostname}:${port}`),
  // HTTPS:
  // cert: Deno.readTextFileSync("./cert.pem"),
  // key:  Deno.readTextFileSync("./key.pem"),
});

Deno.addSignalListener("SIGTERM", () => ac.abort());
Deno.addSignalListener("SIGINT", () => ac.abort());
```

## Run it

```bash
deno run --allow-net --allow-env --allow-read src/server.ts
```

## Deploy to Deno Deploy

Deno Deploy reads the entry script directly. Point your project at `src/server.ts`; the same file you run locally is what runs in production.

```bash
# install once
deno install -gArf jsr:@deno/deployctl

# deploy
deployctl deploy --project=my-api src/server.ts
```

## Dockerfile

```docker
FROM denoland/deno:distroless
WORKDIR /app
COPY . .
EXPOSE 3000
CMD ["run", "--allow-net", "--allow-env", "--allow-read", "src/server.ts"]
```

## Gotchas

- Don't use `Deno.serveHttp`: it's deprecated. The DaloyJS adapter uses `Deno.serve` exclusively.
- On Deno Deploy you don't get `SIGTERM`; the platform manages shutdown. The `AbortController` wiring above is for self-hosted Deno only.
- Use `--allow-net` (and others) explicitly, Deno's default-deny permissions are the point.

## See also

- [Adapters overview](/docs/adapters)
- [Netlify Edge Functions](/docs/adapters/netlify): also Deno-based.

---

Source: https://daloyjs.dev/docs/adapters/deno