Back to Blog
Tutorial9 min read2026-07-01

How to Deploy a Deno App to Production

Deno's security-first permission model and built-in tooling change how you deploy. Here's how to containerize a Deno app, set the right permission flags, and wire in a managed database.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

Deno reimagines the JavaScript runtime with security baked in: no file, network, or environment access unless you explicitly grant it. That permission model is great for safety but means deployment requires a little more intentionality. This guide covers a production Deno deployment.

The permission model is a deployment concern

Unlike Node, Deno runs with zero permissions by default. You opt in per capability:

deno run --allow-net --allow-env --allow-read main.ts

In production, grant the minimum your app needs. A typical web service needs:

  • --allow-net — to listen and make outbound requests.
  • --allow-env — to read configuration and DATABASE_URL.
  • --allow-read — if it reads files (static assets, templates).

You can scope flags further, e.g. --allow-net=0.0.0.0:8000,db.example.com to whitelist specific hosts. This is real, enforceable least-privilege — use it.

A production Dockerfile

Deno publishes official images. Cache dependencies in a layer for faster rebuilds:

FROM denoland/deno:2.0.0
WORKDIR /app

# Cache deps separately for layer caching
COPY deno.json deno.lock ./
RUN deno install

COPY . .
RUN deno cache main.ts

EXPOSE 8000
USER deno
CMD ["run", "--allow-net", "--allow-env", "main.ts"]

deno cache main.ts pre-downloads and compiles dependencies at build time, so the container starts fast and works offline. The official image already includes a non-root deno user.

Writing a server

Deno's built-in HTTP server uses web-standard APIs:

const port = Number(Deno.env.get("PORT") ?? 8000);

Deno.serve({ port, hostname: "0.0.0.0" }, (req) => {
  const url = new URL(req.url);
  if (url.pathname === "/healthz") {
    return new Response(JSON.stringify({ status: "ok" }), {
      headers: { "content-type": "application/json" },
    });
  }
  return new Response("Hello from Deno");
});

Bind to 0.0.0.0 so the container is reachable externally. Deno.serve is production-grade and handles concurrency natively.

A managed database

Deno has first-class PostgreSQL drivers. Using deno-postgres:

import { Pool } from "https://deno.land/x/postgres/mod.ts";

const pool = new Pool(Deno.env.get("DATABASE_URL")!, 5, true);

const client = await pool.connect();
try {
  const result = await client.queryObject`SELECT NOW()`;
  console.log(result.rows);
} finally {
  client.release();
}

The pool's third argument (true) makes connections lazy. Keep the pool size aligned with your database's connection limit across replicas.

Compiling to a single binary (optional)

Deno can compile your app into a self-contained executable:

deno compile --allow-net --allow-env --output server main.ts

The permissions are baked into the binary, and you get a single artifact with no runtime to install — handy for a distroless-style image. For most cloud deployments the container approach above is simpler.

Deploying on PandaStack

  1. 1Create a PostgreSQL database — DATABASE_URL is injected automatically.
  2. 2Connect your repo as a container app. PandaStack detects the Dockerfile and builds via rootless BuildKit.
  3. 3Set any secrets and PORT handling in the dashboard.
  4. 4Push — live build logs stream and you get automatic SSL on custom domains.

Deno's fast startup makes it a good fit for free-tier scale-to-zero. You also get rollbacks and deploy history.

ConcernSetting
Permissions--allow-net --allow-env (scope further)
ServerDeno.serve on 0.0.0.0
Depsdeno cache at build time
Usernon-root deno
DBdeno-postgres pool

Common pitfalls

  • Over-granting permissions--allow-all defeats Deno's main advantage; scope flags.
  • Binding to localhost — unreachable inside a container; use 0.0.0.0.
  • No lockfile — commit deno.lock for reproducible, verifiable dependency builds.
  • Skipping deno cache — slower cold starts and network dependency at runtime.

References

  • Deno deployment guide: https://docs.deno.com/runtime/tutorials/docker/
  • Deno permissions reference: https://docs.deno.com/runtime/fundamentals/security/
  • Deno.serve API: https://docs.deno.com/api/deno/~/Deno.serve
  • deno-postgres driver: https://deno.land/x/postgres
  • deno compile: https://docs.deno.com/runtime/reference/cli/compile/

---

Deno's quick startup and PandaStack's free-tier scale-to-zero are a natural match. Add a managed PostgreSQL database with DATABASE_URL auto-wired and push your repo. Deploy at https://dashboard.pandastack.io

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also