Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Generator powered models
branch: master

This branch is 14 commits behind MokoJs:master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.


Generator-powered, highly extendible models made for use with co.

Build Status


npm install moko

Example Usage

var moko = require('moko'),
    validators = require('moko-validators'),
    mongo = require('moko-mongo');

var User = require('moko');

  .attr('name',  { required: true })
  .attr('email', { format: 'email' })


co(function*() {
  var user = yield new User(); = 'Ryan'; = '';

Early edition...

Moko is currently in active development. There docs might be incomplete, and the essential plugins missing. That being said, you're definitely welcome to play with it and give feedback to help shape the library. If you are interested in joining the organization and contributing your own plugins, please reach out.


moko is the spiritual successor to modella, updated for use with upcoming ECMA 6 generators.

moko provides bare-bones models. By providing powerful hooks and events, plugins are able to greatly extend functionality.


Moko provides two types of events, async (powered by generators) and sync (powered by functions). async events happen before an operation and allow you to mutate the data, while sync events allow you to react to changes. In general, async events end with ing (eg. saving, creating, initializing).

Plugin authors are also encouraged to emit their own events to make it easy for users to hook into the plugins. See the guide below.

Built in async events:

Moko will emit the following async events. Notice that you must use generators for async events, although your generators do not necessarily need to yield themselves.

  • initializing(attrs) - called when a model is first initialzed
  • saving(dirty) - called before save
  • creating(dirty) - called before save when the model did not exist prior
  • updating(dirty) - called before save when the model did exist prior


User.on('initializing', function*(user, attrs) { = 'Bob';

var user = yield new User({name: 'Stephen'});
console.log( // Logs "Bob";
User.on('creating', function*(user, attrs) {
  attrs.createdAt = new Date();

var user = yield new User({name: 'Stephen'});
User.on('saving', function*(u, dirty) {
  var others = yield User.find({name:}).count();
  if(others) throw new Error('Will not save with non-unique name');

Built in sync events:

Function events are emitted after something happens on the model.

Built in events include:

  • initialize(instance) - called after an instance is done initializing
  • change(attr, newVal, oldVal) - called when an attr changes
  • change attr(newVal, oldVal) - called when attr changes
  • save - called after save
  • create - called after save when model did not exist prior
  • update - called after save when model did exist prior

User.on('change name', function(user, name, old) {
  console.log("User changed name from %s to %s", old, name);

co(function*() {
  var user = yield new User({name: 'Bob'}); = 'Steve';

Fire and forget email sending on user-creation.

User.on('create', function(user) {
  emails.sendWelcomeEmail(, function() { }) // anonymous callback fn


Something went wrong with that request. Please try again.