About me

Michael L Perry

Improving Enterprises

Principal Consultant


User login

Jinaga - A universal back-end for single page web applications

When you're working on a web application, you want to keep your head in the Angular/Knockout/Ember, CSS, and HTML. You want to keep thinking about the front end.

But then you get to a point where you need to save some data, record a user action, or query to update the page. And so you stop what you are doing and switch to the back end.

Advantages over 3-tier

The three-tier style of creating web applications leads you to create a back-end MVC controller for each kind of resource that the app might want to save. The controller transforms it into a document or a set of relational rows and saves it to the database. Then another controller (or at least another method) queries based on parameters, reads that data back out of the database, and translates it into the JSON that the front end requires.

For each new application feature, you need to touch all three tiers: front-end, back-end, and database.

A universal back end cuts out all that extra work. The front end simply creates a JSON document and saves it, all from client code. Then it queries for data again using JSON, and the universal back end does all the work.

For each new application feature, you just write front-end code.

No (application-specific) Back End

There are several universal back ends (Firebase, Hoodie, Parse, and others listed at nobackend.org). Jinaga is different. It uses immutable facts to ensure that changes are easy to distribute across several devices. Immutability makes conflict detection and resolution simple.

Another advantage is that Jinaga is open source. Many of the above backends-as-a-service are commercial products. You host your data on their servers and pay them a monthly fee. But Jinaga is not a product. You install it on your own server and host your own data.

Simple API

There are only two functions that you will call from your front-end code. First, call fact in order to save some data:

  type: "Task",
  list: {
    type: "TodoList",
    name: "Chores"
  description: "Take out the trash"

This records the fact that there is a task with the description "Take out the trash". Furthermore, it relates this fact to the list with the name "Chores". We can now call watch to query for all tasks within that list:

function tasksInList(l) {
  return {
    type: "Task",
    list: l

var chores = {
  type: "TodoList",
  name: "Chores"

function taskAdded(task) {
  // Render the task in the UI

j.watch(chores, [tasksInList], taskAdded);

This will query for all tasks currently in the list, and add them all to the UI. But it doesn't stop there. It will continue adding tasks to the UI as the user enters more: it will call taskAdded whenever fact is called.

And one more thing. It might be called on another browser. That works, too. There's one single API function for loading, refreshing, and synchronizing data.

Get Started

To get started using Jinaga, install Mongo, Node, and Bower for your platform. Then get the NPM and Bower packages for Jinaga, and write your very own universal back end:

var JinagaDistributor = require("jinaga/jinaga.distributor.server");
var MongoProvider = require("jinaga/jinaga.mongo");
var url = 'mongodb://localhost:27017/dev';
var port = 8888;

var mongo = new MongoProvider(url);
JinagaDistributor.listen(mongo, mongo, port);

Start the app and connect from the front end:

var j = new Jinaga();
j.sync(new JinagaDistributor("ws://localhost:8888/"));

That's the last time you'll need to touch the back end.