Skip to main content

HTTP server: File based Routing

If you've used frameworks like Next.js, you might be familiar with file based routing. You add a file in a specific directory and it automatically becomes a route. This example demonstrates how to create a simple HTTP server that uses file based routing. Note: This is not an exhaustive example and is meant to be a starting point. Permissions required: `--allow-net`: To start the HTTP server. `--allow-read`: To read files from the file system for dynamic import.

Edit on Github
This is a simple module that exports a `GET` handler for the /users route. You may implement other HTTP methods such as `POST`, `PUT`, and `DELETE` in this file.
./users.ts
export function GET(_req: Request): Response {
  return new Response("Hello from user.ts", { status: 200 });
}
This is the main file that will be used to route requests.
./main.ts
async function handler(req: Request): Promise {
Extract the path and method from the request.
./main.ts
  const url = new URL(req.url);
`path` could be any valid URL path such as /users, /posts, etc. For paths like `/users`, the file `./users.ts` will be imported. However, deeper paths like `/org/users` will require a file `./org/users.ts`. So, you can create nested routes by creating nested directories and files.
./main.ts
  const path = url.pathname;
method could be any of the HTTP methods such as GET, POST, PUT, DELETE, etc.
./main.ts
  const method = req.method;
  let module;
  try {
Dynamically import the module based on the path. Notice the `.` prefix before the path. The path is relative to the current file. Be aware of caveats when using dynamic imports. [Read more](https://docs.deno.com/deploy/api/dynamic-import)
./main.ts
    module = await import(`.${path}.ts`);
  } catch (_error) {
If the module is not found, return a 404 response.
./main.ts
    return new Response("Not found", { status: 404 });
  }
Check if the module has the method handler.
./main.ts
  if (module[method]) {
Call the method handler with the request.
./main.ts
    return module[method](req);
  }
If the method handler is not found, return a 501:Not Implemented response.
./main.ts
  return new Response("Method not implemented", { status: 501 });
}
Start the server on the default port.
./main.ts
Deno.serve(handler);

Run this example locally using the Deno CLI:

deno run --allow-net --allow-read https://docs.deno.com/examples/http-server-file-router.ts/main