Back to Blog
3 min readTutorial

Deploying Deno Applications: From Development to Production

Learn how to deploy Deno applications to production with Deno Deploy, Docker, and other platforms

Deploying Deno Applications

Deploying Deno apps is straightforward with modern platforms. Here's how to deploy to production securely and efficiently.

Deployment Options

1. Deno Deploy (Easiest)

# Install deployctl
deno install --allow-all --no-check -r -f https://deno.land/x/deploy/deployctl.ts

# Deploy
deployctl deploy --project=my-app server.ts

server.ts:

Deno.serve((req) => new Response("Hello from Deno Deploy!"));

2. Docker

Dockerfile:

FROM denoland/deno:1.38.5

WORKDIR /app
COPY . .

RUN deno cache server.ts

EXPOSE 8000

CMD ["deno", "run", "--allow-net", "--allow-read", "--allow-env", "server.ts"]

Build and run:

docker build -t my-deno-app .
docker run -p 8000:8000 my-deno-app

3. Kubernetes

deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deno-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: deno-app
  template:
    metadata:
      labels:
        app: deno-app
    spec:
      containers:
      - name: deno-app
        image: my-deno-app:latest
        ports:
        - containerPort: 8000
        env:
        - name: PORT
          value: "8000"

4. DigitalOcean/AWS/GCP

# Using systemd service
# /etc/systemd/system/deno-app.service
[Unit]
Description=Deno Application
After=network.target

[Service]
Type=simple
User=deno
WorkingDirectory=/home/deno/app
ExecStart=/home/deno/.deno/bin/deno run --allow-net --allow-read --allow-env server.ts
Restart=always

[Install]
WantedBy=multi-user.target

# Enable and start
sudo systemctl enable deno-app
sudo systemctl start deno-app

Production Best Practices

1. Environment Variables

// config.ts
const config = {
  port: parseInt(Deno.env.get("PORT") || "8000"),
  database: {
    url: Deno.env.get("DATABASE_URL") || "",
    poolSize: parseInt(Deno.env.get("DB_POOL_SIZE") || "10"),
  },
  auth: {
    secret: Deno.env.get("AUTH_SECRET") || "",
  },
};

export default config;

2. Logging

import * as log from "@std/log";

await log.setup({
  handlers: {
    console: new log.handlers.ConsoleHandler("DEBUG"),
    file: new log.handlers.FileHandler("INFO", {
      filename: "./app.log",
      mode: "a",
    }),
  },
  loggers: {
    default: {
      level: "DEBUG",
      handlers: ["console", "file"],
    },
  },
});

log.info("Server starting...");
log.error("Error occurred", { error });

3. Health Checks

router.get("/health", (ctx) => {
  ctx.response.body = {
    status: "healthy",
    timestamp: new Date().toISOString(),
    uptime: Deno.metrics().ops.now / 1000,
  };
});

4. Graceful Shutdown

const server = Deno.serve({ port: 8000 }, handler);

Deno.addSignalListener("SIGTERM", async () => {
  console.log("SIGTERM received, shutting down gracefully");
  await server.shutdown();
  await cleanup();
  Deno.exit(0);
});

Security Checklist

  • Use specific permissions (not --allow-all)
  • Validate environment variables
  • Use HTTPS in production
  • Implement rate limiting
  • Add security headers
  • Sanitize user input
  • Use helmet-style middleware

Monitoring

// Simple metrics endpoint
let requestCount = 0;
let errorCount = 0;

router.get("/metrics", (ctx) => {
  ctx.response.body = {
    requests: requestCount,
    errors: errorCount,
    memory: Deno.memoryUsage(),
  };
});

Performance Tips

  1. Cache dependencies
deno cache --reload server.ts
  1. Use appropriate permissions
deno run --allow-net=:8000 --allow-read=./static server.ts
  1. Enable HTTP/2
Deno.serve({
  port: 8000,
  cert: await Deno.readTextFile("./cert.pem"),
  key: await Deno.readTextFile("./key.pem"),
}, handler);

Conclusion

Deploy Deno apps with confidence using:

  • Deno Deploy for serverless
  • Docker for containers
  • Systemd for VPS
  • Proper logging and monitoring
  • Security best practices

Start deploying today!

👨‍💻

Jordan Patel

Web Developer & Technology Enthusiast