Breadbox is an MVC framework for Node.js. It is currently in beta and should not be used without expectation of breaking changes.

Most Node frameworks provide little functionality out of the box. This allows for immense flexibility, but requires that you find and implement middleware to do almost anything. Breadbox strikes a different balance, providing more functionality out of the box at the expense of flexibility. It strives to provide a feature set broad enough to meet the needs of a standard web application, with an emphasis on avoiding bloat while maintaining security. Out of the box, it includes:

Getting Started

First install Node if you haven't, and make a directory for your project.

mkdir my-project
cd my-project

Install Breadbox.

npm install breadbox --save

In your project directory, create a file for your app. We'll use index.js.

// my-project/index.js

From your terminal, in your project's root directory, run node index, where index is the name of the file you created. You should now be able to see Breadbox's default index page at http://localhost:1337. Here you can create an admin user, which allows you to use a built-in interface for CRUD (create, read, update, delete) operations on models and users.

Hello World

In your project's root directory, make file called index.js:

const breadbox = require('breadbox');

	controllers: {
		'/index': resolve => {
		    resolve({ person: "World" });

In your project's root directory, create views/index.mnla:

Hello, <:person:>!

In your terminal, enter the root directory of your project and start the server:

node index

In your browser, navigate to http://localhost:1337 and you should see the following:

Hello, World!

The breadbox module


require('breadbox')( [Object] config );

When called as a function, the breadbox module accepts a config object and runs your app. The config object may have the following properties:

After initializing your application, you can use require('breadbox') to access the breadbox object. It is also available globally as global.breadbox.

The breadbox object exposes the following methods and properties:


breadbox.db is an object that provides a set of lightweight data access methods. It works by storing and manipulating JSON files in the data folder of your project's root directory.

breadbox.db exposes the following methods:

All breadbox.db methods return promise objects which resolve when the operation succeeds.

const db = require('breadbox').db;

// Get a blog post
db.get('posts').then(posts => {
	let article = {
		title: posts[0].title,
		body: posts[0].content


Breadbox uses a slightly enhanced promise implementation internally - specifically, any number of arguments can be passed to resolve(). This implementation is exposed to you in case you would like to take advantage of this enhancement.

The breadbox.promise method accepts a function that performs an asyncronous operation. This function is passed resolve and reject arguments, which can be called to handle the result of the operation.

breadbox.promise returns an object with two methods:

For example:

const breadbox = require('breadbox');

function getData() {

	return breadbox.promise((resolve, reject) => {

		doAsync('operation', (err, data) => {
			if (err) {
			} else {
				resolve(data, 'This is a message');


getData().then((data, message) => {
	console.log(data, message);
}).catch(error => {

Error Handling

Traditionally, error handling has been a pain in Node. All asyncronous operations need to be able to return errors, which means developers have to devote a lot of lines of code to error checking. breadbox.handle provides a convienent way to safely return a styled error page if necessary, or else continue running seamlessly.


breadbox.handle( [any] error, ([number] status), ([object] headers), ([boolean] die) ): returns a promise object that will resolve only if error is falsy. It accepts three arguments:

A typical use case:

const fs = require('fs'),
handle = require('breadbox').handle;

fs.readFile('/path/to/file.json', { encoding: 'utf8' }, (err, data) => {

	handle(err).then(() => {

		let successfulData = JSON.parse(data);


breadbox.attempt( [function] try, ([function] catch) ): a wrapper for try/catch. If the execution of try raises an exception, breadbox.attempt passes the error to catch, or to breadbox.handle if catch is undefined.

Additionally, breadbox.attempt returns a promise which will be resolved with the result of a successful call to try.

const attempt = require('breadbox').attempt;

attempt(() => {


}, err => {
	console.log('global.possiblyDefined is undefined');

}).then(data => {
	console.log(' is ' + data);


The purpose of a controller is to get the data necessary to render a template. It does this by creating a context object and passing it to a resolve() function. When creating a context object, a controller has access to stored data as well as a number of data sources on the request, such as the session, query string, POST data, and the URL itself.

Controllers are passed to the breadbox configuration object. For readability, you'll want to use require or import to store them as modules in their own files:

const breadbox = require('breadbox');

	controllers: {
		'/index': require('./controllers/index'),
		'/docs': require('./controllers/docs')


The keys on the controllers object are used to match a requested URL to a particular controller function. Because all controllers are associated with views, '.html' extensions are ignored. For example, '' and '' would both match a controller with the key '/page'. In either case, by default breadbox would look for the corresponding view at /views/page.mnla. The url '/' is normalized to match the controller key '/index', and correspondes to the view at /views/index.mnla.


If a user must be logged in to see a particular route, append the route key with '|authenticate'. Unauthenticated requests to the page will then automatically redirect to /login (or settings.loginPage), where a successful login attempt will redirect back to the correct route.

const breadbox = require('breadbox');

	controllers: {
		'/change-password|authenticate': require('./controllers/change-password')

After authentication, user data can be found in request.sess.

Dynamic Routes

Often, parts of a URL are required but dynamic. For example, a typical blog post URL might look like ''. In this case, we want to use the same controller no matter what the post ID is, and we need to make the post ID available to the controller so that it can get the post from a data store. Breadbox's solution for this to use route parameters (not to be confused with query strings).

const breadbox = require('breadbox');

	controllers: {
		'/posts/<:id:>': require('./controllers/post')

Now, the post ID will be made available to the controller as


The value of each property in the controllers object is a function. The first argument passed to this function is a resolve function. To send a response, this function can be passed up to three values:

const breadbox = require('breadbox');

	controllers: {
		'/index': resolve => {
		    resolve( { context: "Foo" }, 'home.html', { 'Set-Cookie': 'bar=baz' } );


The second argument passed to each controller function is a request object. This object has a number of properties that can give you information about the user and their request, as well as methods for doing cool stuff:


Breadbox uses a fast, simple template engine (published separately as Manila). It has no proprietary template syntax - it simply uses JavaScript.


<: expression :>: This tag will be replaced with the HTML-escaped result of evaluating the expression or variable with the current context.

<:: expression ::>: Use three carets instead of two to prevent HTML-escaping of the expression.

// Controller
let context = {
	name: 'Mike',
	html: '<h1>test</h1>'
<!-- views/index.mnla -->
My name is <: name :>.
<: html :>
<:: html ::>

<!-- output: -->
My name is Mike.


<: include path/to/file :>: Includes the content of the named template as part of the current template. path/to/file is relative to views/ unless overwritten during configuration.


With the exception of ES2015 template strings, you can use whatever JavaScript you like to iterate and conditionally render markup. Here are some examples:


<: if (expression) { :>
	<p>This markup renders if expression is truthy.</p>
<: } else { :>
	<p>This markup renders if expression is falsy</p>
<: } :>

Array Loops

<: list.forEach(item => { :>
<: }) :>

Object Loops

<: for (key in obj) { :>
	<li><:key:> is <:obj[key]:></li>
<: } :>


Breadbox sends the following headers with every request by default:

Content-Type: # based on filetype
Cache-Control: max-age=2419200 # 1 month cache
Keep-Alive: timeout=15, max=100
X-XSS-Protection: 1
X-Content-Type-Options: nosniff

When you supply headers with a response, they are merged with the default headers.


The one area in which Breadbox does not prioritize simplicity is security. Only two third-party dependencies were used in the development of Breadbox: Formidable for parsing form data buffer streams, and bcrypt for hashing and salting passwords. Session IDs and CSRF tokens are generated using Node's built-in crypto module.

CSRF Protection

To combat CSRF attacks, all POST requests must include a token field generated by the breadbox.csrf.makeToken method.

breadbox.csrf.makeToken( [object] request ): accepts a request object - the same one passed to a controller function - and returns a promise object that resolves with two values:

// A controller function:
const csrf = require('breadbox').csrf;

module.exports = (response, request) => {

	csrf.makeToken(request).then((headers, token) => {

		context.token = token;

		response.resolve(context, undefined, headers);
<!-- form.html: -->
<form action="/" method="post">
	<input type="hidden" name="token" value="<:token:>">
	<input type="text" name="data">
	<input type="submit">