Skip to content
henri

The versatile JavaScript framework

An easy to learn, Rails-like, server-side rendered framework for Node.js. Models, controllers, routes and React views, with real ORMs and hot reload out of the box.

Rails-like structure

app/models, app/controllers, app/views, config/routes.js. If you know Ruby on Rails, you already know where everything goes.

Server-side rendered React

Pages live in app/views/pages and are rendered by Next.js. Controllers hand them data with res.render(); the same endpoint answers JSON when asked for it.

Real ORMs

Mongoose for MongoDB, Sequelize for MySQL, MariaDB, PostgreSQL and MSSQL. A zero-config disk store for prototyping. Models are global, like in Rails.

GraphQL built in

Add a graphql key to a model and its types and resolvers are merged into a single schema, served by Apollo Server and queryable from res.render().

Hot reload everything

Controllers, models, routes, workers and configuration reload on save. Press R in the terminal to list the loaded routes.

Generators

henri new, henri generate model, henri generate scaffold. Users get password hashing, sessions and roles for free.

config/routes.js
module.exports = {
'resources tasks': 'tasks',
'/': 'tasks#index',
};
app/controllers/tasks.js
module.exports = {
index: async (req, res) => {
res.render('/tasks', { data: { tasks: await Task.find() } });
},
create: async (req, res) => {
await Task.create(req.body);
res.redirect('/');
},
};
app/views/pages/tasks.js
import withHenri from '@usehenri/react';
const Tasks = ({ data }) => (
<ul>
{data.tasks.map((task) => (
<li key={task._id}>{task.name}</li>
))}
</ul>
);
export default withHenri(Tasks);