An MVC for NodeJS built on Koa

View on GitHub
Home | Documentation | Core | CLI | Install

Co.Koa header


Co.Koa’s controllers are a facade for the koa-router module; it is advised that you read said documentation in conjunction with the below. Should you wish to perform custom logic against the Koa-router module, you can access it via Co.Koa’s app.js as coKoa.router:


With co-koa-cli installed, you can install a fresh controller template by typing co-koa-cli --createController <ControllerName> in your project’s root directory. (do not append the name with the word “service!”)


Controllers support the following verbs:

module.exports = function ($) {
  return {
    async 'GET /' (ctx, next) {},
    async 'PUT /' (ctx, next) {},
    async 'POST /' (ctx, next) {},
    async 'PATCH /' (ctx, next) {},
    async 'DELETE /' (ctx, next) {}

just as with koa-router, Co.Koa exposes the ctx and next arguments. See koa-router's documentation for more details.


Each method within a controller is an “action” that the server can perform on request. Co.Koa automatically routes by convention. for example: if you have a “BookController” with a method called GET /Foo then get requests will be routed to Book/Foo.

The order in which your actions are defined is important. If a URI expects to be supplied parameters and shares the same request verb as other actions, it must be defined after the other URIs.

For Example:

module.exports = function ($) {
  return {
    async 'GET /foo' (ctx) {},
    async 'GET /:id' (ctx) {},

In the above instance, if :id was before foo, your controller would treat a “/foo” request as if it was an :id parameter.

Multiple Request Verbs

As of co-koa-core@^1.15.0, your actions can be assigned multiple request verbs via a comma-separated list. For Example:

async 'DELETE,PUT /Author/:id' (ctx) {
  try {
    if (ctx.request.body.hasOwnProperty('childId')) {
      ctx.body =
        await someService
            ctx.request.method === 'DELETE' ? '$pull' : '$push'])
    } else throw new Error('childId was not found.');
  } catch (e) {
    ctx.body = { success: false, error: e.message };


Each project is supplied with an "IndexController.js". Routes within this file will point directly to the virtual root of your web application. For example, in a development instance at localhost:3000, GET / will route to the address localhost:3000/. It is strongly advised that, at most, you supply only the following actions to this controller:

module.exports = function IndexController ($) {
  return {
    async 'GET /' (ctx) {},
    async 'POST /' (ctx) {},
    async 'PUT /' (ctx) {},
    async 'PATCH /' (ctx) {},
    async 'DELETE /' (ctx) {}

Rendering Pages

Koa supports static and dynamic content. To load .hbs files within your views folder, supply an asynchronous call to ctx.render() with the view’s name and, if necessary, an object containing variables to be used by the rendering engine:

'GET /foo': async (ctx) => {
  await ctx.render('FooView', { bar: 'bar' });

the fs module’s capacity for streaming files is exposed via the Dependency Manager. In this fashion we can easily render static HTML from our resources file (ensure that the router informs the browser to handle html):

async 'GET /' (ctx) {
  ctx.type = 'html';
  ctx.body = $(':html').stream('index');