Originally the plan was to get familiar with Next.js and Prisma by making a simple boilerplate for it. Turns out a few commands is all it takes to generate a basic working app. Let’s get started and add Next.js:

npx create-next-app my-app

To add Typescript run touch tsconfig.json && yarn dev and Next.js will generate the needed files and install packages. Then add Prisma:

yarn add -D @prisma/cli
yarn prisma init

Prisma created a .env file with the database connection url. dotenvenc npm package can be used to generate an encrypted .env.enc file containing the production variables. Locally .env can be filled by hand (Primsa requires a .env file and doesn’t support having separate for .env.production and .env.staging).

Basic deployment script that can be refined:

#!/bin/bash
set -e

echo 'Pulling latest from master…'
git pull origin master

echo 'Installing node_modules…'
yarn install --frozen-lockfile

echo 'Decrypting .env.env file…'
./node_modules/.bin/dotenvenc -d $DOTENVENC_KEY

echo 'Running Prisma migrations and generate…'
yarn prisma migrate deploy && yarn prisma generate

echo 'Building Next.js…'
yarn build

echo 'Start or reload app in cluster mode…'
pm2 startOrReload start -i max

Add ecosystem.config.js file for node manager pm2:

module.exports = {
  apps: [
    {
      name: 'my-app',
      script: 'yarn',
      args: 'start',
      autorestart: true,
      watch: false,
      instances: 'max',
      exec_mode: 'cluster',
    },
  ],
};

Make it executable chmod +x deploy.sh. Depending on your deployment setup, you can ssh into the server and execute this script when merging into master. A few considerations:

  • build on the server since both Prisma and potentially Next.js requires access to production database
  • add DOTENVENC_KEY=password to your .bashrc for decrypt .env.enc
  • git, pm2, node, yarn and a database needs to be installed on the system (additionally nginx can be used for static files)

To improve code quality add yarn add -D prettier, yarn add -D eslint && npx eslint --init and then npx mrm lint-staged to ensure it runs before committing.