keystonejs / keystone-6-heroku-example

A simple example project of showing how you might deploy Keystone 6 to Heroku
15 stars 15 forks source link
heroku keystonejs

Keystone 6 on Heroku

A simple example project showing how one might develop and deploy a KeystoneJS 6 backend to Heroku.

keystone-heroku-2

The app code in this project is based heavily on the with-auth example project from the main Keystone repo. It demonstrates some of the powerful APIs and tools Keystone provides and the gratifying developer experience it enables.

If you haven't heard about Keystone, it's a powerful GraphQL-based headless CMS, written in TypeScript It has some terrific features out of the box, is easy to extend, and a joy to use. There's documentation covering all the APIs and field types used in this project, as well as guides to take you further.

If you get stuck, hit us up on the KeystoneJS Slack and search (or post) under the [keystonejs] tag on Stack Overflow.

How to Use This Repo

There are different ways to approach this repo depending on what you're trying to achieve:

Deploy Directly to Heroku

Deploy Directly to Heroku

This magical button 👆 takes a copy of this repo, builds it into an image and runs it on a Heroku dyno with the Postgres addon. All you need to get started is a Heroku account.

These resources are created on the free tier so, naturally, have some performance limitations and will "sleep" if no request are made for a few minutes. With this option you also won't be able to modify the source code or data schema (for that, you'll need to setup a local dev environment, see below). Regardless this is a great, low investment way to play with the Keystone Admin UI from a user perspective.

Develop Locally

This codebase can be run and developed on your local machine by setting up a simple development environment.

First, ensure you have the following tools installed:

If you're on MacOS and use Homebrew, you can install all these at once:

brew install git node yarn postgresql

If you're on a different platform, click though the links above and follow the relevant instructions.

Once the prerequisites are installed we can download the app code:

# Download the repo
git clone https://github.com/keystonejs/keystone-6-heroku-example
cd keystone-6-heroku-example

# Install the node packages
yarn

# Start the app
yarn dev

Then, point your browser to localhost:3000. You'll be prompted to set an email address and password before being taken to the Keystone Admin UI.

Modifying the App

This app is extremely simple – it has only a two lists and intentionally avoids the more advanced Keystone functionality (like hooks, the document field, access control, etc.). This has let us organised most of the Keystone code into two files:

You'll need to restart the Keystone process before changes made to the source code are reflected in the app. To do so simply stop the process (Ctrl + c) and re-run yarn dev.

Start a New Project

There are many way of creating a Keystone application. You can install packages manually to create something from scratch (ie. yarn add @keystone-next/keystone) or use a guided process like create-keystone-app. Alternatively, you can copy and modify an existing app like this repo.

To do so, fork or otherwise copy these files to your own repository then follow the instructions above to setup a local development environment.

Note, Keystone is usually used as a headless CMS, meaning your users will visit a separate, frontend application or website, which uses the Keystone API behind the scenes. The creation and deployment of this frontend app is beyond the scope of this guide.

Deployment

Heroku supports a number of deployment strategies all of which can be used with Keystone. You've already seen the "Deploy to Heroku" button above. It's a fun demo but isn't suited for actually developing and repeatedly deploying an application to production. Here we'll use the "push to deploy" strategy. This process uses the Heroku CLI to create and configure a new app then git to deploy changes.

First, ensure you have the Heroku CLI installed and authenticated to your Heroku account. If you're on MacOS the suggested method is Homebrew (for other platforms, see the download options):

# Get the Heroku cli (if you don't have it already)
brew tap heroku/brew && brew install heroku

# Follow the prompts to authenticate
heroku auth:login

Once the CLI tooling is authenticated, run these commands from the root of your app repo. You'll need to replace my-keystone-app with a key that will identify you app. This will be used to identify your app later and must be globally unique.

# Create the new app and configure a free postgres addon
# This also adds a git remote to your repo called "heroku"
heroku create my-keystone-app --addons=heroku-postgresql:hobby-dev

# Adding a SESSION_SECRET env var will allow sessions to persist between dyno restarts and deploys
heroku config:set SESSION_SECRET=$(head -c50 /dev/urandom | base64 | tr -dc 'A-Za-z0-9' | head -c50)

# Deploy your latest commit by pushing the main branch to the heroku remote
git push heroku main

It'll take a few minutes to build and deploy, then your app will appear online. The last section of the build output will give you the public URL, similar to this:

remote: -----> Launching...
remote:        Released v1
remote:        https://my-keystone-app.herokuapp.com/ deployed to Heroku

Migrations

If you're developing an app, sooner or later, you're going to need to change the database structure.

The first time you ran yarn dev on your dev machine Keystone created a database and setup the initial schema by applying the SQL in the /migrations/20210825070616_initial_schema directory. This migration was generated by Keystone based on the contents of schema.ts. You can leverage this same functionality to create your own migrations.

For example, lets open schema.ts and add a phone field to the Person list, like this:

Person: list({
  fields: {
    name: text({ isRequired: true }),
    phone: text(),  // <- New!

    // Existing fields ...
  },
});

Re-running yarn dev will prompt us to create and apply a migration representing this change:

✨ There has been a change to your Keystone schema that requires a migration
✔ Name of migration … adding phone numbers
✨ A migration has been created at migrations/20210825230709_adding_phone_numbers
✔ Would you like to apply this migration? … yes
✅ The migration has been applied

Behind the scenes, this magic is being performed by Prisma and Prisma Migrate. The resultant SQL (in /migrations) can be committed to git like any other file. Once it's applied, your database, GraphQL schema and Admin UI will all reflect the updated list schema.

This codebase is setup to automatically applied outstanding migrations as part of the build process executed by Heroku. You can see this in package.json – the build script is keystone-next build && keystone-next prisma migrate deploy.

In practise this means database changes are run against your Heroku database a short time before the new version of the application is rolled out. As such, you should ensure your database changes are backwards compatible with the previous release of your app (or risk runtime errors while the deployments are occurring).

There are many strategies for deploying and coordinating app updates and migrations. The approach we've taken here is simple and works sufficiently well for this infrastructure setup but your app may have different needs. See the CLI docs for the underlying commands used.

Next Steps

For ideas on what's possible with Keystone, see the guides section of the website, checkout the roadmap and stay tuned to the project updates.