Skip to content
🚀 The future of KeystoneJS
Branch: master
Clone or download
Type Name Latest commit message Commit time
Failed to load latest commit information.
.changeset Prepare release (#1434) Jul 19, 2019
.circleci Add `validateInput()` hook to AdminUI Fields on Item Details page (#1230 Jun 12, 2019
api-tests Prepare release (#1429) Jul 19, 2019
demo-projects Prepare release (#1429) Jul 19, 2019
docs Change 'fields' directory name to 'lists' (#1423) Jul 18, 2019
flow-typed Field type build tool (#993) Apr 18, 2019
jest Support arbitrary mongo joins in GraphQL API Aug 27, 2018
packages Prepare release (#1434) Jul 19, 2019
test-projects Prepare release (#1429) Jul 19, 2019
website Prepare release (#1429) Jul 19, 2019
.all-contributorsrc Add @1337cookie as a contributor (#1424) Jul 18, 2019
.eslintignore initial create-app Mar 7, 2019
.eslintrc.js Fix failing CI tests (#1070) Apr 29, 2019
.flowconfig Move all packages into the @keystone-alpha namespace and reset versio… Mar 7, 2019
.gitignore Build arch-ui and apollo-helpers (#623) Jan 18, 2019
.prettierignore Add .next to .prettierignore May 3, 2019
.remarkignore add remark-cli to `yarn lint` and `yarn format` Apr 24, 2019 Prepare release (#1429) Jul 19, 2019
LICENSE Initial setup Apr 6, 2018
Procfile windows compatible npm scripts (#1299) Jun 13, 2019 Revert to start command for create-keystone-app (#1303) Jun 14, 2019 Move frontmatter into comments (#1250) May 27, 2019
app.json Fix heroku deployment and add app.json necessary for review apps (#941) Mar 27, 2019
babel.config.js Compile Controller base class to ES5 so that non-native classes can e… May 24, 2019 run `remark . --output` Apr 24, 2019
netlify.toml windows compatible npm scripts (#1299) Jun 13, 2019
package.json Correctly lowercase @keystone-alpha/fields-mongoid for release… (#1430) Jul 19, 2019
yarn.lock Ensure resolveInput for list receives result from fields (#1421) Jul 19, 2019



Welcome to Keystone 5, the development project for the future of KeystoneJS.

schema => ({ GraphQL, AdminUI })

KeystoneJS is a scalable platform and CMS for Node.js applications.

Keystone 5 introduces first-class GraphQL support, a new extensible architecture, and an improved Admin UI.

It is currently in alpha and under intensive development by Thinkmill and contributors around the world.

What's new?

Keystone 5 is a complete re-imagining of KeystoneJS for the future. It builds on the lessons we learned over the last 5 years of the Keystone's history and focuses on the things we believe are the most powerful features for modern web and mobile applications.

This means less focus on hand-holding Node.js template-driven websites and more focus on flexible architecture, a powerful GraphQL API with deep access control features, an extensible Admin UI and plugins for rich field types, file and database adapters, and session management.

We believe it's the ideal back-end for rich React / Vue / Angular applications, Gatsby and Next.js websites, Mobile applications and more. It also makes a great Headless CMS.


This project is currently very much in the alpha phase of development. There are known bugs, missing features, and limited documentation. APIs have not been finalised and may change with each release.

To make this clear, we're currently publishing all packages to the @keystone-alpha scope on npm.


Getting Started

Quick start

To get up and running with a basic project template, run the following commands.

yarn create keystone-app my-app
cd my-app
yarn start

For more details and system requirements, check out the 5 Minute Quick Start Guide.

Demo Projects

These projects are designed to show off different aspects of KeystoneJS features at a range of complexities (from a simple Todo App to a complex Meetup Site).

See the demo-projects/ docs to get started.

Manual Setup

yarn add @keystone-alpha/keystone @keystone-alpha/fields @keystone-alpha/adapter-mongoose @keystone-alpha/app-graphql @keystone-alpha/app-admin-ui

Add a script to your package.json:

  "scripts": {
    "dev": "keystone"

Create a file index.js:

const { Keystone }        = require('@keystone-alpha/keystone');
const { MongooseAdapter } = require('@keystone-alpha/adapter-mongoose');
const { Text }            = require('@keystone-alpha/fields');
const { GraphQLApp }      = require('@keystone-alpha/app-graphql');
const { AdminUIApp }      = require('@keystone-alpha/app-admin-ui');

const keystone = new Keystone({
  name: 'Keystone To-Do List',
  adapter: new MongooseAdapter(),

keystone.createList('Todo', {
  fields: {
    name: { type: Text },

module.exports = {
  apps: [
    new GraphQLApp(),
    // Setup the optional Admin UI
    new AdminUIApp(),

Now you have everything you need to run a Keystone instance:

yarn dev

Keystone will automatically detect your index.js and start the server for you:

  • http://localhost:3000/admin: Keystone Admin UI
  • http://localhost:3000/admin/api: generated GraphQL API
  • http://localhost:3000/admin/graphiql: GraphQL Playground UI

Custom Server

In some circumstances, you may want to do custom processing, or add extra routes the server which handles the API requests.

A custom server is defined in server.js which will act as the entry point to your application (in combination with index.js which defines your schema) and must handle executing the different parts of Keystone.

Create the server.js file:

const express = require('express');
const { keystone, apps } = require('./index');

keystone.prepare({ apps, dev: process.env.NODE_ENV !== 'production' })
  .then(({ middlewares }) => {
    const app = express();
    app.get('/', (req, res) => {
      res.end('Hello world');
  .catch(error => {

You'll need to change the dev script in your package.json to run the server file with node like this.

- "dev": "keystone"
+ "dev": "NODE_ENV=development node server.js"

Note that when using a custom server, you will no longer get the formatted console output when starting a server.

For more, see the Custom Server Discussion.

Production Build

When getting ready to deploy your app to production, there are performance optimisations which Keystone can prepare for you.

Add these scripts to your package.json:

  "scripts": {
    "build": "keystone build",
    "start": "keystone start"

Run yarn build to generate the following outputs(this output could change in the future):

└── dist/
    └── admin/

To run your keystone instance, run the start script.

yarn start

Production Build Artifacts


A static export of the Admin UI lives here. Built from your code setting up the keystone instance, this export contains list and field config information tightly coupled to the API.

Adding Authentication

See Authentication docs.

To setup authentication, you must instantiate an Auth Strategy, and create a list used for authentication in index.js:

const { Keystone, PasswordAuthStrategy } = require('@keystone-alpha/keystone');
const { MongooseAdapter } = require('@keystone-alpha/adapter-mongoose');
const { Text, Password }  = require('@keystone-alpha/fields');
const { AdminUIApp } = require('@keystone-alpha/app-admin-ui');

const keystone = new Keystone({
  name: 'Keystone With Auth',
  adapter: new MongooseAdapter(),

keystone.createList('User', {
  fields: {
    username: { type: Text },
    password: { type: Password },

const authStrategy = keystone.createAuthStrategy({
  type: PasswordAuthStrategy,
  list: 'User',
  config: {
    identityField: 'username', // default: 'email'
    secretField: 'password',   // default: 'password'

module.exports = {
  apps: [
    new AdminUIApp({ adminPath: '/admin', authStrategy })

NOTE: It will be impossible to login the first time you load the Admin UI as there are no Users created. It is recommended to first run an instance of Keystone without an auth strategy, create your first User, then re-enable the auth strategy.


All source code should be formatted with Prettier. Code is not automatically formatted in commit hooks to avoid unexpected behaviour, so we recommended using an editor plugin to format your code as you work. You can also run bolt format to prettier all the things. The lint script will validate source code with both ESLint and prettier.


Keystone 5 is set up as a monorepo, using Bolt.

First, clone the Keystone 5 repository

git clone

Then make sure you've got Bolt installed:

yarn global add bolt

Also make sure you have a local MongoDB server running (instructions). If you don't have it installed, on MacOS use Homebrew (run these once):

brew install mongodb
brew services start mongodb

Then install the dependencies and start the test project:

bolt dev

See demo-projects/ for more details on the available demo projects.


Keystone uses Jest for unit tests and Cypress for end-to-end tests. All tests can be run locally and on CircleCI.

Unit Tests

To run the unit tests, run the script:

bolt jest

Unit tests for each package can be found in packages/<package>/tests and following the naming pattern <module>.test.js. To see test coverage of the files touched by the unit tests, run:

bolt jest --coverage

To see test coverage of the entire monorepo, including files which have zero test coverage, use the special script:

bolt coverage

End-to-End Tests

Keystone tests end-to-end functionality with the help of Cypress. Each project (ie; test-projects/basic, test-projects/login, etc) have their own set of Cypress tests. To run an individual project's tests, cd into that directory and run:

bolt cypress:run

Cypress can be run in interactive mode from project directories with its built in GUI, which is useful when developing and debugging tests:

cd test-projects/basic && bolt cypress:open

End-to-end tests live in project/**/cypress/integration/*spec.js. It is possible to run all cypress tests at once from the monorepo root with the command:

bolt cypress:run

NOTE: The output from this command will mix together the output from each project being tested in parallel. This is only recommended as sanity check before pushing code.

Running a CI environment locally

Setting up CircleCI CLI tool

Install the circleci cli tool:

If you've already got Docker For Mac installed (recommended)

brew install --ignore-dependencies circleci

If you do not have Docker installed

brew install circleci

Then make sure docker is able to share the following directories (in Docker for Mac, go Preferences > File Sharing):

  • The keystone 5 repo
  • /Users/<your username>/.circleci

Run CI tests locally

Make sure Docker is running.

Execute the tests:

# Clean up the node_modules folders so everything is installed fresh
yarn clean

# Run the circle CI job
circleci local execute --job simple_tests

Where simple_tests can be replaced with any job listed in .circleci/config.yml under the jobs: section.

Code of Conduct

KeystoneJS adheres to the Contributor Covenant Code of Conduct.


Copyright (c) 2019 Jed Watson. Licensed under the MIT License.

You can’t perform that action at this time.