Skip to content

a first look at oak

  • Oak
  • Deno
  • Deno Deploy
a first look at oak cover image


All of this project’s code can be found in the First Look monorepo on my GitHub.


Oak is a middleware framework for Deno’s native HTTP server and Deno Deploy. It is influenced by Koa (hence the anagram) and includes a middleware router inspired by @koa/router.


Deno ships as a single executable with no dependencies. However, we will also need to install deployctl for Deno Deploy.

Install Deno Executable

There are various ways of installing Deno depending on your operating system. If you are using Mac or Linux, the official Shell install script is recommend.

curl -fsSL | sh

You can find a list of different installation methods on the official documentation and the deno_install repo.

Install deployctl

With deployctl you can run your Deno Deploy scripts on your local machine. Your scripts are run in the Deno CLI, with the correct TypeScript types for Deno Deploy. After installing Deno, deployctl can be installed using the following command.

deno install \
  --allow-read \
  --allow-write \
  --allow-env \
  --allow-net \
  --allow-run \
  --no-check \
  --force \

You may need to set the PATH variable as seen below but with your own path to the deno executable in place of /Users/ajcwebdev.

export PATH="/Users/ajcwebdev/.deno/bin:$PATH"

Create Project Files

All we need is a directory containing an index.js file.

mkdir ajcwebdev-oak
cd ajcwebdev-oak
touch index.js
echo '.DS_Store' > .gitignore

Create Deno Server

Before diving into Oak, it’s useful to see the underlying server code they are building upon. The Deno Standard Library has an http module with a basic hello world application. Save the following code in index.js:

// index.js

import { listenAndServe } from "[email protected]/http/server.ts"

  () => new Response("Hello from Deno on Localhost 8080")

console.log("Server running on localhost:8080")

Run Deno Server

deno run \
  --allow-net index.js \
  --watch \
Server running on localhost:8080

Open localhost:8080.


Create Oak Server

Oak is a third party module for Deno hosted on their service. To import one of these modules, use the following format for code URLs:[email protected]/FILE_PATH

If you leave out the version it will default to the most recent version released for the module. The Deno docs recommend pinning to a specific version to avoid unexpected breaking changes. At the time of this writing, the current version of Oak is[email protected]/mod.ts.

Application Class

The Application class coordinates managing the HTTP server, running middleware, and handling errors that occur when processing requests. Two methods are generally used:

  • Middleware is added via the .use() method.
  • The .listen() method starts the server and then processes requests with the registered middleware.

Once the server is open, before it starts processing requests, the application will fire a "listen" event, which can be listened for via the .addEventListener() method.

// index.js

import { Application } from "[email protected]/mod.ts"

const app = new Application()

app.use((ctx) => {
  ctx.response.body = "Hello from Oak on Localhost 8080"

app.addEventListener('listen', () => {
  console.log(`Server running on localhost:8080`)

app.listen({ port: 8080 })

The middleware is processed as a stack, where each middleware function can control the flow of the response. When the middleware is called, it is passed a context (ctx) and reference to the “next” method in the stack.

  • .response accesses the Response object to form the response sent back to the requestor.
  • The .body method returns a representation of the request body.

Return to localhost:8080.


Respond with HTML

To respond with HTML instead of plain text, use .headers.set on ctx.response and set the Content-Type to text/html.

// index.js

import { Application } from "[email protected]/mod.ts"

const app = new Application()

app.use((ctx) => {
  ctx.response.body = "<h2>Hello from Oak on Localhost 8080</h2>"
  ctx.response.headers.set("Content-Type", "text/html")

app.addEventListener('listen', () => {
  console.log(`Server running on localhost:8080`)

app.listen({ port: 8080 })

Return to localhost:8080 to see the change.


Add Router

The Router class produces middleware which can be used with an Application to enable routing based on the pathname of the request.

// index.js

import { Application, Router } from "[email protected]/mod.ts"

const router = new Router()
const app = new Application()

router.get("/", (ctx) => {
  ctx.response.body = "<h2>Hello from Router on Localhost 8080</h2>"
  ctx.response.headers.set("Content-Type", "text/html")

router.get("/about", (ctx) => {
  ctx.response.body = "<h2>This page tells you about stuff</h2>"
  ctx.response.headers.set("Content-Type", "text/html")


app.addEventListener('listen', () => {
  console.log(`Server running on localhost:8080`)

app.listen({ port: 8080 })

Return to localhost:8080 to see the change.


Open localhost:8080/about to see the new about page.


Deno Deploy

Deno Deploy is a distributed system that runs JavaScript, TypeScript, and WebAssembly at the edge, worldwide. It is a multi-tenant JavaScript engine running in 25 data centers across the world.

Run Oak Server with deployctl

You can run your script like it would run on Deno Deploy with deployctl. Include --no-check so TypeScript doesn’t explode in a giant fireball of errors. You can also add the --watch flag to automatically restart the script when any modules in the module graph change.

deployctl run index.js --no-check --watch

If you return to localhost:8080 there will be no change in the application.

Initialize GitHub Repository

git init
git add .
git commit -m "finally, another project named after a tree"
gh repo create ajcwebdev-oak
git push -u origin main

Install the Deno Deploy GitHub App

We will be deploying this script from a URL on GitHub. Install the Deno Deploy GitHub App.


Sign Up for Deno Deploy

Sign up for a Deno Deploy account and connect the account to your GitHub. You will be taken to a page for your projects.


Create Deno Deploy Project

Click “New Project” and enter a name for your project.


After creating your project you are given the option of using existing templates.


Connect GitHub Repository

Since we will not be using a template, scroll down to connect the GitHub repository we just created.


Paste the raw GitHub URL for your function.


Click “Link” and go to


You can use the project overview page to review your project’s settings, add/remove domains, or view the deployment logs.