DEV Community

Maciej Krawczyk
Maciej Krawczyk

Posted on • Originally published at Medium on

Keystone.js 101


Photo by Bicanski on Pixnio

Introduction

Some time ago I was working on small project consisting website and app to collect research data. It’s a kind of project I am typically working at for my clients. In most cases my stack for that kind of project consists of WordPress as headless CMS, Next.js front, and custom-built Node.js app for data collecting. But often I feel this is kind of overkill. Especially in that last case. So I decided to look for better solution, best in the way to solve CMS and data collecting app in one. After brief research I’ve decided to stick to Keystone.js, it has all I need. But also it required a bit of customization (more about in previous articles, here and here). These customizations were so interesting I’ve decided to write about them, but when I was writing last article I realized that they were pretty niche and specialized. And there’s hardly any introduction to Keystone.js in its newest version, released at the end of last year. And that’s why I’ve decided to take brake from writing about custom fields and components and concentrate on simple, beginner-friendly introduction to Keystone.

New version of Keystone.js was released at the end of 2021. Basically it’s CMS system build with Express.js backend and admin UI in Next.js. But also it’s features packed including types safe Prisma ORM and TypeScript to elevate developer experience as stated in release blog post:

We extended Keystone’s foundations in Node, Express, and JavaScript, by adding Prisma to take care of the database layer and NextJS to power Keystone’s Admin UI. We also introduced a strongly-typed developer experience to make Keystone **the most advanced TypeScript Headless CMS**.

Thanks to usage of Prisma Keystone can generate migrations every time there’s update in data schema. It definitely allows co concentrate on building application business logic without concern about low level implementation details. In some cases it may not be what we want but in general it’s nice to have it working out of the box. There may be some performance issues due to ORM’s issue with 1+N queries, but it can be mitigated easily. Additionally, we have here built-in support for GraphQL what is always pleasant.

Ok, all that features are rally impressive, but what use case is prefect for Keystone? First it’s CMS, so managing content for websites, landing pages or blogs with custom frontends are usages where it shines. But not only, due to its wide possibilities of creating data structure, it can be used in many more cases. E.g., e-commerce — the challenge is only in designing right models for cart, and products, additional functionalities like payment processing can be added using built in extensibility of underlying Express.js.

Installation

I think It’s the high time to get our hands dirty and start our own Keystone instance.

Dependencies

Basically only thing we require to have is Node.js installed. Out of the box Keystone comes with SQLite, so there’s no need for additional database. But always we can switch to PostgreSQL, for now I am gonna stick to first option in sake of simplicity.

Let’s start

To begin with we only require one command. Open your terminal and type:

$ npx create-keystone-app
Enter fullscreen mode Exit fullscreen mode

First, CLI will ask for name of our app, let’s try simple-keystone-blog:

npx create-keystone-app output

Next, as prompted cd into that folder (assuming You are using Linux or Mac, if You need, use Windows equivalent commands), and start project with yarn dev and open http://localhost:3000 in browser.

Here You can set initial user account and login into admin dashboard. Out of the box there are two lists already created. User and Post, so we have all the basics to start writing a blog. Also, we can access all the data via GraphQL API or use sandbox accessible under http://localhost:3000/api/graphql.

Files structure

Ok, let’s have a look on the files structure in our project:

Files structure

First two folders contains auto-generated views for admin UI, third dependencies to NPM packages. keystone.db, schema.graphql and schema.prisma are database itself, GraphQL and ORM configuration, each one is also auto-generated, based on our changes. Last three important files are keystone.ts, auth.ts and schema.ts. First contains whole configuration of our project — database configuration and imported from other two auth (session) settings and lists definitions.

Auth settings work really nice out of the box, and I won’t focus on them If You are curious of them check the docs. Much more interesting are lists settings, let’s have a look on them.

Schemas

This file exports object of type of Lists, which contains configurations for all the lists visible (and invisible) in admin UI. There are three defined here: User, Post and Tag. Each one calls function list with additional configuration object. This object can have up to six properties, but only one is mandatory — fields. It holds list of all the fields in that list (with their additional config). Amount of field types here is not huge, but it’s enough for all basic needs (more), it contains fields for all data types, files and images, relations to other lists and rich text editor. Rest of the props holds more advance configuration options, like display options in ui prop, side effects associated with this list in hooks prop, additional database or GraphQL config in db and graphql. Additionally, some of this config properties can be used directly on the level of each field to extend their functionality.

All this config options gives us wide possibility to build complex schemas for each list including side effects allowing to integrate external tools and extend it further. In topic of extensibility there are two additional things worth mention. On top of all the fields in main config object (keystone.ts) we can modify setting of underlying Express.js server. Options here are pretty basic, except one — extendExpressApp. Basically this option allows us to add more REST endpoints or middleware to our backend. Second important option is extendGraphqlSchema, generally it does the same job as previous one, but allows adding custom GraphQL resolvers.

Summary

I know I’ve barely scratched the surface of what really Keystone.js can do, but on the other hand I hope I’ve showed the real potential in it. At first glance it looks like pretty basic CMS with limited options. But when we dig deeper there are tons of possibilities and after careful planing and clear requirements it may turn out that we don’t need to build another custom system. Instead, use something nice as a base and extend it.

That’s the third article in series about Keystone.js. In this one I’ve decided to take step back, and get to basics. I hope it’s enough to convince You to give it a try. Next week, I’m getting back to series and custom components, this time we are going to extend JSON field and use it as data for building pages navigation menu.

Top comments (0)