Skip to Page NavigationSkip to Page NavigationSkip to Content
Keystone 6 is now in General Availability!

Release: 24th November 2021

The Release Candidate for Keystone 6 General Availability has arrived! Within youโ€™ll find numerous improvements across the project. โญ๏ธ

After this release, we will be moving Keystone 6 to General Availability and promoting the project to the @keystone-6 namespace on npm.

We highly recommend you upgrade to this release:

"@keystone-next/auth": "37.0.0",
"@keystone-next/cloudinary": "12.0.0",
"@keystone-next/document-renderer": "5.0.0",
"@keystone-next/fields-document": "14.0.0",
"@keystone-next/keystone": "29.0.0",
"@keystone-next/session-store-redis": "9.0.0",

โš ๏ธ ย  This release contains breaking changes! Please backup your data before upgrading and read the instructions below.

Shorter Relationship Names ๐Ÿค

โš ๏ธ ย  Breaking change! Please follow the guidance below to avoid losing data.

The names of one-sided and two-sided, many-many relationships has been shortened. Two-sided many-many relationship names contain only the left-hand side names now; and the _many suffix has been dropped from one-sided many-many relationships.

This reduces the probability that you will exceed PostgreSQL's 63 character limit for identifiers with typical usage.

There are two different ways you can update your schema:

  • Explicitly set the db.relationName on many-to-many relations, allowing your database to remain unchanged.

  • Rename your many-to-many relations and tables using a migration, changing your database.

Set db.relationName on many to many relations

Rather than doing a migration, you can set the new field property db.relationName, for either side of a many-to-many relationship field.

If set to the existing relation name, your database will remain unchanged.

For example, given a schema like this:

Post: list({
fields: {
tags: relationship({ ref: 'Tag.posts', many: true }),
},
}),
Tag: list({
fields: {
posts: relationship({ ref: 'Post.tags', many: true }),
},
}),

Before this release, the generated Prisma schema looked like this:

// This file is automatically generated by Keystone, do not modify it manually.
// Modify your Keystone config when you want to change this.
datasource postgresql {
url = env("DATABASE_URL")
provider = "postgresql"
}
generator client {
provider = "prisma-client-js"
output = "node_modules/.prisma/client"
engineType = "binary"
}
model Post {
id String @id @default(cuid())
tags Tag[] @relation("Post_tags_Tag_posts")
}
model Tag {
id String @id @default(cuid())
posts Post[] @relation("Post_tags_Tag_posts")
}

By adding db: { relationName: 'Post_tags_Tag_posts' } to one side of the many-to-many relationship; you can preclude yourself from a migration.

It doesn't matter which side of the relationship you put this property, but it should be only on one side; otherwise you will receive an error.

Post: list({
fields: {
tags: relationship({ ref: 'Tag.posts', many: true, db: { relationName: 'Post_tags_Tag_posts' } }),
},
}),
Tag: list({
fields: {
posts: relationship({ ref: 'Post.tags', many: true }),
},
}),

Rename your many relation tables using a migration

For example, given a schema like this:

Post: list({
fields: {
tags: relationship({ ref: 'Tag.posts', many: true }),
},
}),
Tag: list({
fields: {
posts: relationship({ ref: 'Post.tags', many: true }),
},
}),

When updating to this change, and running yarn dev, Keystone will prompt you to update your schema.

โš ๏ธ Warning: DO NOT APPLY THE AUTOMATICALLY GENERATED MIGRATION!
You will lose your data. Only apply the migration if you want to DROP your data.

If using useMigrations: true, Keystone will follow the typical migration flow and offer to apply an automatically generated migration.

If using useMigrations: false, Keystone will follow the typical flow and offer to automatically migrate your schema.

On PostgreSQL, Prisma will generate a migration that looks something like this:

/*
Warnings:
- You are about to drop the `_Post_tags_Tag_posts` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "_Post_tags_Tag_posts" DROP CONSTRAINT "_Post_tags_Tag_posts_A_fkey";
-- DropForeignKey
ALTER TABLE "_Post_tags_Tag_posts" DROP CONSTRAINT "_Post_tags_Tag_posts_B_fkey";
-- DropTable
DROP TABLE "_Post_tags_Tag_posts";
-- CreateTable
CREATE TABLE "_Post_tags" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "_Post_tags_AB_unique" ON "_Post_tags"("A", "B");
-- CreateIndex
CREATE INDEX "_Post_tags_B_index" ON "_Post_tags"("B");
-- AddForeignKey
ALTER TABLE "_Post_tags" ADD FOREIGN KEY ("A") REFERENCES "Post"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_Post_tags" ADD FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;

You need to modify it so that it looks like this with the old and new table names for your schema substituted:

ALTER TABLE "_Post_tags_Tag_posts" RENAME TO "_Post_tags";
ALTER INDEX "_Post_tags_Tag_posts_AB_unique" RENAME TO "_Post_tags_AB_unique";
ALTER INDEX "_Post_tags_Tag_posts_B_index" RENAME TO "_Post_tags_B_index";
ALTER TABLE "_Post_tags" RENAME CONSTRAINT "_Post_tags_Tag_posts_A_fkey" TO "_Post_tags_A_fkey";
ALTER TABLE "_Post_tags" RENAME CONSTRAINT "_Post_tags_Tag_posts_B_fkey" TO "_Post_tags_B_fkey";

On SQLite, Prisma will generate a migration that looks something like this:

/*
Warnings:
- You are about to drop the `_Post_tags_Tag_posts` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropTable
PRAGMA foreign_keys=off;
DROP TABLE "_Post_tags_Tag_posts";
PRAGMA foreign_keys=on;
-- CreateTable
CREATE TABLE "_Post_tags" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL,
FOREIGN KEY ("A") REFERENCES "Post" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY ("B") REFERENCES "Tag" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "_Post_tags_AB_unique" ON "_Post_tags"("A", "B");
-- CreateIndex
CREATE INDEX "_Post_tags_B_index" ON "_Post_tags"("B");

You need to modify it so that it looks like this with the old and new table names for your schema substituted:

ALTER TABLE "_Post_tags_Tag_posts" RENAME TO "_Post_tags";
DROP INDEX "_Post_tags_Tag_posts_AB_unique";
DROP INDEX "_Post_tags_Tag_posts_B_index";
CREATE UNIQUE INDEX "_Post_tags_AB_unique" ON "_Post_tags"("A", "B");
CREATE INDEX "_Post_tags_B_index" ON "_Post_tags"("B");

Query Engine Switch ๐Ÿš‚

Keystone now uses Prisma's Node-API Query Engine instead of the Binary Query Engine. This should improve the performance of operations using Prisma.

From our initial testing, performance has increased significantly when getting large amounts of data and is marginally better for smaller amounts.

See the Prisma docs for more details.

Node Engines ๐Ÿ’ฝ

Keystone officially supports running on LTS versions of Node.js - this is currently version 14 and 16. We've updated our engine values throughout the project to reflect this.

We recommend you run Node.js ^14.15 or ^16.13 for the best Keystone experience.

Miscellaneous Fixes โš™๏ธ

  • Fixed the init/sign in page showing for a short amount of time after submitting on the init/sign in page and seeing a loading spinner.

  • Fixed clear button not removing inline relationships when used in the document field.

  • Relationship field now respects ui.displayMode: 'cards' in the create view.

  • The Set as Authenticated Item/Add Authenticated Item button is now hidden if the relationship field already has the authenticated item.

  • Fixed ui.isAccessAllowed not being respected in the admin meta query when no session strategy was defined.

  • The item page in the Admin UI no longer crashes when failing to fetch an item.

  • The admin meta query now bypasses ui.isAccessAllowed for sudo contexts.

  • Fixed doing multiple writes at the same time on SQLite causing an timeout immediately.

Credits ๐Ÿ’ซ

Like this release? Give us a star on GitHub!

Complete Changelog ๐Ÿ“œ

You can also view the verbose release notes for this release on GitHub.