All controllers should return a response to be sent back to the client. A response can be sent in many of the built in ways that horsepower supports.


Strings can be sent as a response and will automatically be converted to a full HTTP response with a header of text/html.

Router.get('/', () => 'Hello World')


When something that is returned which is not a Response object or string, it will be converted to a full json HTTP response with a header of application/json.

Router.get('/arr', () => ['a', 'b', 'c'])
Router.get('/obj', () => ({ a: 'a', b: 'b', c: 'c' }))
Router.get('/bool', () => true)
Router.get('/num', () => 123)

Response Object

The response object has multiple methods for returning different types of responses each with their own unique feature.


html is the most basic response, it is the same as returning a string in the controller.

Router.get('/', client => client.response.html('Hello World'))


json is another basic return type, it can be automatically executed by something that isn't a Response object or a string. However if you need to return a string as json (since strings get converted to html instead of json) it can be done using this built in method.

Router.get('/', client => client.response.json('Hello World'))


render will render a template, and return it with a full HTTP response with a header of text/html.

Horsepower has its own rendering engine which uses mix files. However, other rendering engines are supported. Horsepower will use the correct rendering engine based on the the file extension passed to renderer. This will allow for the usage of multiple rendering engines in the same project.

  • Horsepower – must pass a .mix extension to the renderer
  • Pug – must pass a .pug extension to the renderer
  • Mustache– must pass a .mustache extension to the renderer
  • Handlebars– must pass a .hbs extension to the renderer

Note: You must manually install the package to render with a particular extension. Rendering engines do not come pre-installed (This includes the horsepower rendering engine).

Router.get('/', client => client.response.render('main.mix'))


cached acts exactly the same as render except that once it has rendered the template, it saves the resulting html into a cache. Once the page has loaded a two or more times the file will be loaded from the cache unless it has expired in which case it will re-render the template.

Note: Files with dynamic routes can be cached, however, this could potentially generate lots of cached files that are saved on the server.

Router.get('/', client => client.response.cached('main.mix', 3600))


download will force a file download to be saved to the clients computer. This is done by setting the Content-Disposition header.

There are two ways to force a download on the client, the first way is to send the download response and pass a buffer as the second parameter.

Router.get('/videos/movie', async client => {
  let resources = Storage.mount('resources')
  return'movie.mpeg', await'videos/movie.mpeg'))

The second way to force a download is to pass a path as a string to the second parameter. The Content-Type header will automatically be added when a string is passed.

Router.get('/videos/movie', client => {
  let resources = Storage.mount('resources')
  return'movie.mpeg', resources.toPath('videos/movie.mpeg'))


file is the exact same as download except that it doesn't set the Content-Disposition header. This is useful for sending files to the client that the browser will automatically handle.


A client can be redirected in two ways. One way is by the name of the route and the other is by a physical http location.


to will redirect a client to a particular route as long as the route has a name attached to it.

Router.get('/', () => '<h1>Welcome Home</h1>').name('home')

Router.get('/redirect', client =>'home'))


location will redirect a client to a physical location on the internet. This could be within the current application or to a completely different website.

Router.get('/google', client => client.response.redirect.location('//'))