Nullstack is a web framework that makes coding fun again.
Write the backend and frontend of a feature in a single isomorphic component with zero boilerplate or glue code.
class WaifuCounter extends Nullstack {
  // runs in the server
  static async getWaifus({ database }) {
    const sql = "SELECT COUNT(*) FROM WAIFUS";
    return database.query(sql);
  }
  // runs in the client
  async countWaifus() {
    this.waifus = this.getWaifus()
  }
  // runs wherever is best
  render() {
    return (
      <button onclick={this.countWaifus}>
        Count: {this.waifus}
      </button>
    );
  }
}


On the first render you'll get SEO ready HTML optimized for the first paint of your route in a single request using local functions with zero JavaScript dependencies in the client bundle

After the content is served and the network is idle Nullstack JavaScript is loaded, the state of the application is restored through hydration and it becomes a single page application

Subsequent server functions will fetch JSON from an automatically generated microservice API, deserialize the response, update the aplication state, and rerender the page out of the box
class WaifuCreator extends Nullstack {
  // extracted into a microservice
  static async insertWaifu({ database, name }) {
    const sql = "INSERT INTO waifus (name) VALUES (?)";
    return database.query(sql, name);
  }
  // invokes the microservice
  async create() {
    this.insertWaifu({ name: "Nulla-Chan" })
  }
  // render in the DOM
  render() {
    return (
      <button onclick={this.create}>
        Create Waifu
      </button>
    );
  }
  
}
You write features for products. The compiler extracts your front end code and replaces all static async functions with calls to microservices

class Vanilla extends Nullstack {
  // variables are just variables
  count = 0;
  // mutations reflect in the dom
  increment() {
    this.count++
  }
  
  // 'this' is bound by default
  render() {
    return (
      <button onclick={this.increment}> 
        {this.count}
      </button>
    )
  }
}Your components are just POJOs. Take advantage of the existing ecosystem while you write JavaScript or TypeScript as it is supposed to be, and see the result reflected in the DOM.

class Modern extends Nullstack {
  // params are injected on every function
  renderWaifu({ params }) {
    return (
      <p> Hi i'm {params.name} </p>
    )
  }
  // routes can have dynamic segments
  render() {
    return (
      <div class="not-class-name">
        <Waifu route="/waifus/:name" />
        <a href="/waifus/Nulla">
          NullaChan
        </a>
      </div>
    )
  }
}JSX tags follow the HTML standard, routes are simple attributes you can assign to any tag, and links are just anchor tags. You will find out that Nullstack is just a modern version of your current stack.

class Batteries extends Nullstack {
  name = 'Nulla-Chan';
  happy = false;
  action() {
    console.log('event already prevented')
  }
  render() {
    return (
      <form onsubmit={this.action}>
        {/* two way bindings */}
        <input bind={this.name} />
        {/* object events */}
        <button onclick={{ happy: true }}>
          Hug {this.name}
        </button>
      </form>
    )
  }
}Nullstack has a lot of out of the box shortcuts that were extracted out of repeating patterns in real projects instead of architecture books. Give it a try and you will get it!
