Note: tinyhttp is not yet finished. Therefore, documentation is incomplete.


The app object is the whole tinyhttp application with all the middleware, handlers and settings.

import { App } from '@tinyhttp/app'

const app = new App()

app.get('/', (req, res) => {
  res.send('hello world')


The app object has methods for

The tinyhttp application object can be referred from the request object and the response object as req.app, and res.app, respectively.


noMatchHandler(req, res)

Handler if none of the routes match. Should return 404 Not found.

import { App, Request, Response } from '@tinyhttp/app'

const app = new App({
  noMatchHandler: (req: Request, res: Response) => {
    res.status(404).end('Not found :(')

  .get('/', (req, res) => {
    res.send('hello world')

onError(err, req, res)

A middleware to catch server errors. Error can be anything. Should return 500 Internal Server Error.

import { App, Request, Response } from '@tinyhttp/app'

const app = new App({
  onError: (err, req, res) => {
      message: err.message,

  .get('/', (req, res) => {
    res.send('hello world')


tinyhttp application has a list of settings to toggle various application parts. All of them are opted out by default to achieve the best performance (less extensions, better performance).

import { App } from '@tinyhttp/app'

const app = new App({
  settings: {
    networkExtensions: true,

app.use((req, res) => void res.send(`Hostname: ${req.hostname}`)).listen(3000)

Here's a list of all of the settings:


Enabled a list of Request object extensions related to network.


Enables 2 properties - req.fresh and req.stale:


Subdomain offset for req.subdomains. Defaults to 2.


Bind the app as a reference to the actual app to req.app and res.app. Disabled by default.



The app.locals object has properties that are local variables within the application.

// => 'My App'

// => '[email protected]'

Once set, the value of app.locals properties persist throughout the life of the application, in contrast with res.locals properties that are valid only for the lifetime of the request.

You can access local variables in templates rendered within the application. This is useful for providing helper functions to templates, as well as application-level data.

app.locals.title = 'My App'
app.locals.strftime = require('strftime')
app.locals.email = '[email protected]'


app.parent points to a parent App object, e.g. the app that was mounted to.

const app = new App()

const subapp = new App()



<ref *1> App {
  middleware: [],
  mountpath: '/',
  apps: {
    '/': App {
      middleware: [],
      mountpath: '/',
      apps: {},
      parent: [Circular *1]


Coming soon...



Routes an HTTP request, where METHOD is the HTTP method of the request, such as GET, PUT, POST, and so on, in lowercase. Thus, the actual methods are app.get(), app.post(), app.put(), and so on.

Routing methods

Not all methods aren't added yet.


This method is like the standard app.METHOD() methods, except it matches all HTTP verbs.

The following callback is executed for requests to /secret whether using GET, POST, PUT, DELETE, or any other HTTP request method:

app.all('/secret', (req, res, next) => {
  console.log('Accessing the secret section ...')
  next() // pass control to the next handler

The app.all() method is useful for mapping “global” logic for specific path prefixes or arbitrary matches. For example, if you put the following at the top of all other route definitions, it requires that all routes from that point on require authentication, and automatically load a user. Keep in mind that these callbacks do not have to act as end-points: loadUser can perform a task, then call next() to continue matching subsequent routes.

app.all('*', requireAuthentication, loadUser)


Routes HTTP GET requests to the specified path with the specified handler functions.

app.get('/', (req, res) => {
  res.send(`${req.method || 'GET'} request to homepage`


Routes HTTP POST requests to the specified path with the specified handler functions.

app.post('/', (req, res) => {
  res.send(`${req.method || 'POST'} request to homepage`


Routes HTTP PUT requests to the specified path with the specified handler functions.

app.put('/', (req, res) => {
  res.send(`${req.method || 'PUT'} request to homepage`)


Routes HTTP DELETE requests to the specified path with the specified handler functions.

app.put('/', (req, res) => {
  res.send(`${req.method || 'PUT'} request to homepage`)


Mounts the specified middleware function or functions at the specified path: the middleware function is executed when the base of the requested path matches path.


A route will match any path that follows its path immediately with a /. For example: app.use('/apple', ...) will match /apple, /apple/images, /apple/images/news, and so on.

Since path defaults to /, middleware mounted without a path will be executed for every request to the app. For example, this middleware function will be executed for every request to the app:

app.use((req, res, next) => {
  console.log('Time: %d', Date.now())

Middleware functions are executed sequentially, therefore the order of middleware inclusion is important.

// this middleware will not allow the request to go beyond it
app.use((req, res, next) => void res.send('Hello World'))

// requests will never reach this route
app.get('/', (req, res) => res.send('Welcome'))


Register a template engine. Works with any Express template engines that contain a renderFile function.

import { App } from '@tinyhttp/app'
import ejs from 'ejs'

const app = new App()

app.engine('ejs', ejs.renderFile) // map app.engines['ejs'] to ejs.renderFile


Render a file with the engine that was set previously via app.engine. To render and respond with the result, use res.render

import { App } from '@tinyhttp/app'
import ejs from 'ejs'

const app = new App()

app.engine('ejs', ejs.renderFile)

  { name: 'EJS' },
  (err, html) => {
    if (err) throw err
    /* some options */

Almost every engine is supported if it can render a single file. Some engines may have different arguments (for example Pug doesn't require a data object) but you can write a function to have the same arguments.

import { App } from '@tinyhttp/app'
import pug from 'pug'

const app = new App()

const renderPug = (path, _, options, cb) => pug.renderFile(path, options, cb)

app.engine('pug', renderPug)

app.use((_, res) => void res.render('index.pug'))

app.listen(3000, () => console.log(`Listening on http://localhost:3000`))


Returns the mountpath of the app.

const app = new App()
const blog = new App()
const blogAdmin = new App()

app.use('/blog', blog)
blog.use('/admin', blogAdmin)

console.dir(app.path()) // ''
console.dir(blog.path()) // '/blog'
console.dir(blogAdmin.path()) // '/blog/admin'


The req object represents the HTTP request and has properties for the request query string, parameters, body, HTTP headers, and so on.

app.get('/user/:id', (req, res) => {
  res.send(`user ${req.params.id}`)

The req object is an enhanced version of Node.js built-in IncomingMessage object.



Contains the hostname derived from either Host or X-Forwarded-Host HTTP header.

// Host: "example.com:3000"
// => 'example.com'


This property is an object containing a property for each query string parameter in the route.

// GET /search?q=tobi+ferret
// => "tobi ferret"

// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
// => "desc"

// => "blue"

// => "converse"

// GET /shoes?color[]=blue&color[]=black&color[]=red
// => [blue, black, red]


Contains the currently-matched route, a string. For example:

app.get('/user/:id?', function userIdHandler(req, res) {

Example output would be something like this:

  path: '/user/:id?',
  method: 'GET',
  handler: [Function: userIdHandler],
  type: 'route'


This property is an object containing properties mapped to the named route “parameters”. For example, if you have the route /user/:name, then the “name” property is available as req.params.name. This object defaults to {}.

// GET /user/v1rtl

app.get('/user/:name', (req, res) => {
  res.end(`Hello ${req.params.name}!`)
// => v1rtl


Contains the request protocol string: either http or (for TLS requests) https. This property will use the value of the X-Forwarded-Proto header field if present. This header can be set by the client or by the proxy.



A Boolean property that is true if a TLS connection is established. Equivalent to the following:

req.protocol === 'https'


A Boolean property that is true if the request’s X-Requested-With header field is “XMLHttpRequest”, indicating that the request was issued by a client library such as fetch.

// => true


This property can be enabled via freshnessTesting setting

When the response is still “fresh” in the client’s cache true is returned, otherwise false is returned to indicate that the client cache is now stale and the full response should be sent.

When a client sends the Cache-Control: no-cache request header to indicate an end-to-end reload request, this module will return false to make handling these requests transparent.

Further details for how cache validation works can be found in the HTTP/1.1 Caching Specification.

// => true


This property can be enabled via freshnessTesting setting

Indicates whether the request is “stale,” and is the opposite of req.fresh. For more information, see req.fresh.

// => true


Contains the remote IP address of the request.

// => ''


Contains an array of remote IP addresses of the request.

// => [']


This property can be enabled via networkExtensions setting

Contains an array of subdomains. Subdomain offset can be set via subdomainOffset

// dev.node0.example.com

// ['node0', 'dev']


This property can be enabled via bindAppToReqRes setting

Points to a reference of the currently used app.

app.use((req, res) => {
  res.json(req.app.middleware) // send a current middleware array, dunno why but this is just an example



Checks if the specified content types are acceptable, based on the request’s Accept HTTP header field. The method returns the best match, or if none of the specified content types is acceptable, returns false (in which case, the application should respond with 406 "Not Acceptable").

The type value may be a single MIME type string (such as "application/json"), an extension name such as "json", a comma-delimited list, or an array. For a list or array, the method returns the best match (if any).

// Accept: text/html
// => "html"

// Accept: text/*, application/json
// => "html"
// => "text/html"
req.accepts(['json', 'text'])
// => "json"
// => "application/json"

// Accept: text/*, application/json
// => false

// Accept: text/*;q=.5, application/json
req.accepts(['html', 'json'])
// => "json"

For more information, or if you have issues or concerns, see accepts.


Returns the first accepted encoding of the specified encodings, based on the request’s Accept-Encoding HTTP header field. If none of the specified encodings is accepted, returns false.


Returns the first accepted charset of the specified character sets, based on the request’s Accept-Charset HTTP header field. If none of the specified charsets is accepted, returns .false


Returns the specified HTTP request header field (case-insensitive match).

// => "text/plain"

// => "text/plain"

// => undefined


The res object represents the HTTP response that a tinyhttp app sends when it gets an HTTP request.



This property can be enabled via bindAppToReqRes setting

Points to a reference of the currently used app.

app.use((req, res) => {



Sets cookie name to value. The value parameter may be a string or object converted to JSON.

The options parameter is an object that can have the following properties.

Property Type Description
domain string Domain name for the cookie. Defaults to the domain name of the app.
encode Function A synchronous function used for cookie value encoding. Defaults to encodeURIComponent.
expires Date Expiry date of the cookie in GMT. If not specified or set to 0, creates a session cookie.
httpOnly boolean Flags the cookie to be accessible only by the web server.
maxAge number Convenient option for setting the expiry time relative to the current time in milliseconds.
path string Path for the cookie. Defaults to “/”.
secure boolean Marks the cookie to be used with HTTPS only.
signed boolean Indicates if the cookie should be signed.
sameSite boolean | string Value of the “SameSite” Set-Cookie attribute. More info.

All res.cookie() does is set the HTTP Set-Cookie header with the options provided. Any option not specified defaults to the value stated in RFC 6265.

res.cookie('name', 'tobi', {
  domain: '.example.com',
  path: '/admin',
  secure: true,

// Enable "httpOnly" and "expires" parameters
res.cookie('rememberme', '1', {
  expires: new Date(Date.now() + 900000),
  httpOnly: true,


Clears the cookie specified by name. For details about the options object, see res.cookie().

Web browsers and other compliant clients will only clear the cookie if the given options is identical to those given to res.cookie(), excluding expires and maxAge.

res.cookie('name', 'tobi', { path: '/admin' })
res.clearCookie('name', { path: '/admin' })


Ends the response process. The method comes from response.end() of http.ServerResponse..

Can be used to send raw data or end the response without any data at all. If you need to respond with data with proper content type headers set and so on, instead use methods such as res.send() and res.json().



Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string using JSON.stringify().

The parameter can be any JSON type, including object, array, string, boolean, number, or null, and you can also use it to convert other values to JSON.

res.json({ user: 'tobi' })
res.status(500).json({ error: 'message' })


Sends the HTTP response.

The body parameter can be a Buffer object, a string, an object, or an array.

res.send({ some: 'json' })
res.send('<p>some html</p>')
res.status(404).send('Sorry, we cannot find that!')
res.status(500).send({ error: 'something blew up' })

This method performs many useful tasks for simple non-streaming responses: For example, it automatically assigns the Content-Length HTTP response header field (unless previously defined) and provides automatic HEAD and HTTP cache freshness support.

When the parameter is a Buffer object, the method sets the Content-Type response header field to "application/octet-stream", unless previously defined as shown below:

res.set('Content-Type', 'text/html')
res.send(Buffer.from('<p>some html</p>'))

When the parameter is a string, the method sets the Content-Type to "text/html":

res.send('<p>some html</p>')

When the parameter is an Array or Object, Express responds with the JSON representation (same as res.json):

res.send({ user: 'tobi' })
res.send([1, 2, 3])


Sets the HTTP status for the response. It is a chainable alias of Node’s response.statusCode.

res.status(400).send('Bad Request')


Sets the response HTTP status code to statusCode and send its string representation as the response body.

res.sendStatus(200) // equivalent to res.status(200).send('OK')
res.sendStatus(403) // equivalent to res.status(403).send('Forbidden')
res.sendStatus(404) // equivalent to res.status(404).send('Not Found')
res.sendStatus(500) // equivalent to res.status(500).send('Internal Server Error')

If an unsupported status code is specified, the HTTP status is still set to statusCode and the string version of the code is sent as the response body.

res.sendStatus(9999) // equivalent to res.status(9999).send('9999')


Sends a file by piping a stream to response. It also checks for extension to set a proper Content-Type header.

Path argument must be absolute. To use a relative path, specify the root option first.

res.sendFile('song.mp3', { root: process.cwd() }, (err) => console.log(err))

More about HTTP Status Codes


Sets the response’s HTTP header field to value. To set multiple fields at once, pass an object as the parameter.

res.set('Content-Type', 'text/plain')

  'Content-Type': 'text/plain',
  'Content-Length': '123',
  ETag: '12345',

Alias to res.header.

Joins the links provided as properties of the parameter to populate the response’s Link HTTP header field.

For example, the following call:

  next: 'http://api.example.com/users?page=2',
  last: 'http://api.example.com/users?page=5',

Yields the following results:

Link: <http://api.example.com/users?page=2>; rel="next",
      <http://api.example.com/users?page=5>; rel="last"


Sets the response Location HTTP header to the specified path parameter.


A path value of "back" has a special meaning, it refers to the URL specified in the Referer header of the request. If the Referer header was not specified, it refers to "/".

After encoding the URL, if not encoded already, tinyhttp passes the specified URL to the browser in the Location header, without any validation. Browsers take the responsibility of deriving the intended URL from the current URL or the referring URL, and the URL specified in the Location header; and redirect the user accordingly.


Render a template using a pre-defined engine and respond with the result.

import { App } from '@tinyhttp/app'
import ejs from 'ejs'

const app = new App()

app.engine('ejs', ejs.renderFile)

app.use((_, res) => void res.render('index.ejs', { name: 'EJS' }))

app.listen(3000, () => console.log(`Listening on http://localhost:3000`))


Adds the field to the Vary response header, if it is not there already.



Sends a conditional response based on the value in Accept header. For example, if Accept contains html, the HTML option will be sent.

  html: (req, res) => void res.send('<h1>Hello World for HTML</h1>')
  text: (req, res) => void res.send('Hello World for text')

and depending on the Accept header, it will send different responses:

curl -H "Accept: text/html" localhost:3000
# <h1>Hello World for HTML</h1>

curl localhost:3000
# Hello World for text


Redirect to a URL by sending a 302 (or any other) status code and Location header with the specified URL.


// custom status
res.redirect('/some-other-page', 300)


Sets the Content-Type HTTP header to the MIME type as determined by mime.lookup() for the specified type. If type contains the / character, then it sets the Content-Type to type.

// => 'text/html'
// => 'text/html'
// => 'application/json'
// => 'application/json'
// => 'image/png'