Skip to content

Instantly share code, notes, and snippets.

@benloeffel
Last active April 14, 2024 16:57
Show Gist options
  • Save benloeffel/3a73896031ba9c27fa7050619ca9db13 to your computer and use it in GitHub Desktop.
Save benloeffel/3a73896031ba9c27fa7050619ca9db13 to your computer and use it in GitHub Desktop.
PayloadCMS, MongoDB, GitHub and Vercel Setup

Modern Web Application Setup Guide (Next.js & PayloadCMS on GitHub and Vercel)

Welcome to your go-to guide for setting up a modern web application using Next.js and PayloadCMS, hosted on GitHub and deployed via Vercel. Let's begin by establishing the backbone of your application—a MongoDB database. Follow these detailed steps to ensure everything is set up correctly.

Create a MongoDB Database

  1. Start by Logging into MongoDB

  2. Create a New Project

    • After logging in, select the option to create a new project.
  3. Name Your Project

    • Assign a meaningful name to your project, relevant to its purpose.
  4. Tag Your Project

    • Add a tag to help identify the environment type. Use key: environment and value: production.
  5. Proceed to Team Setup

    • Click "Next" to proceed, then add a team member and set their permissions, or select an existing member.
  6. Create the Project

    • Click on "Create Project."
  7. Deploy a Database Cluster

    • Once your project is ready, click on "Create" to deploy a new database cluster.
  8. Select Cluster Type

    • Choose the free "M0" cluster option for a cost-effective start.
  9. Name Your Cluster

    • Name your cluster appropriately, for example, prod-example-app.
  10. Configure Your Cluster

    • Ensure "Add a sample dataset" is unchecked.
    • Choose your cloud provider and region, such as AWS in Frankfurt.
  11. Tag Your Deployment

    • Again, tag your deployment with key: environment and value: production.
  12. Launch Your Cluster

    • Click on "Create Deployment" to finalize the setup.
  13. Set Up Database Access

    • Create a database username, e.g., example-user, and auto-generate a secure password. Remember to store these credentials securely in your password manager.
  14. Establish Connection

    • Once your database is ready, click "Connect," then select "Drivers" to get the connection string.
    • Store the connection string securely for future use. Example format:
      mongodb+srv://example-user:<password>@prod-example-app.1xxerno.mongodb.net/?retryWrites=true&w&maj...
      
  15. Configure Network Access

    • Set network access to "Anywhere" to accommodate the dynamic IP address nature of Vercel deployments.

By following these steps, you're now well on your way to having a robust MongoDB database setup for your application. Next, we'll dive into setting up your project repository on GitHub and deploying via Vercel. Stay tuned, and keep the excitement going!

Create a GitHub Project

Welcome to the next step in setting up your modern web application: creating a GitHub repository. Follow these steps to ensure your project is up and ready for version control and collaboration.

  1. Log Into GitHub

    • Start by navigating to GitHub and logging in with your credentials.
  2. Create a New Repository

    • Once logged in, click on the "New repository" button to start the creation process.
  3. Name Your Repository

    • Provide a meaningful name for your repository, such as example-app, to reflect the nature of your project.
  4. Set Repository Visibility

    • Choose to make the repository private if you wish to restrict access to authorized users only.
  5. Create the Repository

    • Click on "Create repository" to finalize the setup.
  6. Copy Repository SSH String

    • After creating your repository, GitHub will display a variety of connection strings. Copy the SSH connection string, which looks like:
      git@github.com:username/example-app.git
      

This sets the foundation for your project's version control using GitHub. With your repository ready, you can now proceed to push your local code and collaborate with your team effectively. Keep up the great work as you move forward with your project development!

Initial Project Setup

Now that your GitHub repository is ready, let's move on to setting up the project on your local machine and initializing your PayloadCMS application. Follow these steps carefully to ensure a smooth setup.

  1. Create and Navigate to a New Directory

    • Open your terminal and run:
      mkdir example-directory && cd example-directory
      
  2. Clone the Repository

    • Clone your newly created GitHub repository:
      git clone git@github.com:benloeffel/example.git
      
  3. Reorganize the Project Directory

    • Navigate into the cloned directory, move all files up one level, and remove the now empty directory:
      cd example && mv .* ../ && cd .. && rmdir example
      
  4. Create a PayloadCMS Application

    • Start the PayloadCMS application setup using:
      npx create-payload-app@beta
      
  5. Name Your PayloadCMS Project

    • When prompted, provide a project name, for instance:
      example
      
  6. Select a Project Template

    • Choose a suitable template for your project, such as:
      blank-3.0
      
  7. Choose a Database

    • Select the type of database you wish to use (MongoDB or Postgres).
  8. Enter Your MongoDB Connection String

    • Provide the MongoDB connection string you obtained earlier:
      Enter your MongoDB connection string and press enter
      
  9. Install Dependencies

    • Wait for PayloadCMS to install all necessary dependencies.
  10. Finalize Project Directory Structure

    • Again, move all files from the subdirectory to the main directory and remove the empty folder:
      cd example && mv * ../ && mv .* ../ && cd .. && rmdir example
      
  11. Run Your Application

    • Start your application using:
      yarn dev
      
    • Alternatively, follow any specific instructions in your project's README.md.
  12. Initial Git Commit

    • After verifying everything is set up and running correctly, make your initial commit and push to GitHub:
      git add . && git commit -m "initial commit" && git push
      

Congratulations on setting up your project! You're now ready to develop and expand your application further.

Setup Conventional Commits

Ensuring that your project’s commit messages are consistent and standardized is crucial for maintaining the project’s history clarity and aiding in automated tools like semantic release. We'll set up CommitLint to enforce Conventional Commits standards.

  1. Install CommitLint CLI

    • Add the CommitLint CLI tool to your development environment:
      yarn add -D @commitlint/cli
      
  2. Install CommitLint Conventional Ruleset

    • Also, install the conventional configuration for CommitLint to use the widely accepted ruleset:
      yarn add -D @commitlint/config-conventional
      
  3. Create a CommitLint Configuration File

    • Create a new configuration file for CommitLint:
      touch .commitlintrc && code .commitlintrc
      
    • This command will create the file and open it in Visual Studio Code for editing.
  4. Configure CommitLint

    • Copy the following JSON configuration into the .commitlintrc file you just opened:
      {
        "extends": ["@commitlint/config-conventional"],
        "rules": {
          "body-max-line-length": [1, "always", 200]
        }
      }
  5. Commit Your Changes

    • Use CommitLint to commit these new configurations to your repository:
      git add . && git commit -m "chore: add commitlint" && git push
      

By following these steps, you'll have set up a robust system for managing your commit messages, ensuring they are informative and structured, which is beneficial for automated processes and maintaining a clear project history.

Setup Commitizen

Commitizen is a tool that prompts you to fill out any required commit fields at commit time, streamlining your commit process and helping you avoid common formatting issues. Here’s how to set it up:

  1. Install Commitizen

    • Add Commitizen to your project to streamline creating conventional commits:
      yarn add -D commitizen
      
  2. Initialize Commitizen

    • Set up Commitizen with a conventional changelog ruleset:
      npx commitizen init cz-conventional-changelog
      
    • This command modifies your package.json to include Commitizen configuration:
      "config": {
        "commitizen": {
          "path": "./node_modules/cz-conventional-changelog"
        }
      }
  3. Clean Up Package Files

    • Remove the automatically created package-lock.json file, as we are using yarn.lock:
      rm package-lock.json
      
  4. Make Your First Commit Using Commitizen

    • Run Commitizen to start the commit process:
      npx cz
      
    • Follow the prompts to craft a commit message:
      • Choose the type of change: chore
      • Skip the scope by pressing enter directly
      • For the description, enter: add commitizen
      • Skip the long description by pressing enter again
      • Answer "N" for the breaking changes prompt
      • Answer "N" for the affects open issues prompt
  5. Push Your Changes

    • Finalize your changes by pushing them to your repository:
      git push
      

By integrating Commitizen, you ensure that every commit message is consistent and informative, which is essential for managing releases and understanding project history. This setup encourages all team members to adhere to a shared commit message format.

Setup Husky to Use Commitlint in Pre-Commit Hook

Husky is a tool that allows you to easily manage and execute Git hooks, ensuring that your commits, pushes, and more adhere to your project standards. Here's how to configure Husky to use Commitlint to check commit messages:

  1. Install Husky and Initialize

    • Begin by installing Husky and initializing it in your project:
      npx husky-init && yarn install
      
  2. Clean Up Default Hooks

    • Husky creates a sample pre-commit hook that we won't need. Remove this file:
      rm .husky/pre-commit
      
  3. Create Commit Message Hook

    • Set up a new commit-msg hook to run Commitlint each time a commit message is entered:

      npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
      
    • This command creates a .husky/commit-msg file with the following contents:

      #!/usr/bin/env sh
      . "$(dirname -- "$0")/_/husky.sh"
      
      npx --no-install commitlint --edit "$1"
      
  4. Test the Configuration

    • Ensure that everything is set up correctly by making a commit:
      git add . && git commit -m "chore: add husky" && git push
      

This setup will trigger Commitlint to verify your commit messages against the conventional commit format every time you attempt to commit, helping prevent non-compliant messages from entering your repository. This automation significantly enhances the consistency and quality of your project's commit history.

Install Semantic-Release

semantic-release automates the version management and package publishing process, which enhances the efficiency of releasing new versions. Here's how to set it up in your project.

  1. Install Semantic-Release

    • Add semantic-release to your project:
      yarn add -D semantic-release
      
  2. Install and Setup Semantic-Release CLI

    • Install the CLI tool and run the setup:
      yarn add -D semantic-release-cli && npx semantic-release-cli setup
      
  3. Configuration Prompts

    • Follow the setup prompts:
      • Repository privacy: Type Y for a private repository and press enter.
      • NPM registry: Accept the default by pressing enter.
      • NPM username: Enter your npm username and press enter.
      • NPM password: Enter your password and press enter.
      • Two-factor authentication code: Enter your NPM 2FA code and press enter.
  4. GitHub Token

    • Generate a new GitHub personal access token by visiting GitHub Token Page.
      • Ensure permissions are set only for "repo".
      • Set an expiration date, e.g., 30 days. Remember, expired tokens will stop semantic-release from working which can lead to delays and confusion. Document the token's expiration clearly or set a reminder to renew it.
      • After creating the token, copy it and paste it into the semantic-release CLI setup.
  5. Configure CI and Secrets

    • Select GitHub Actions as the CI to use and press Enter.
    • Verify that the NPM_TOKEN is set correctly in the repository secrets on GitHub:
      https://github.com/benloeffel/example/settings/secrets/actions
      
  6. Set Permissions for GitHub Token

    • When creating the token, choose the following permissions:
      Contents: read/write, Issues: read/write, Metadata: read
      
  7. NPM Login and Two-Factor Authentication Setup

    • Log in to npm with the legacy auth type:
      npm login --auth-type=legacy
      
    • Enable two-factor authentication (2FA) in auth-only mode if it isn't already set up:
      npm profile enable-2fa auth-only
      
    • If you encounter any errors and you have previously set up 2FA, try resetting it:
      • Disable 2FA:
        npm profile disable-2fa
        
      • Re-enable it:
        npm profile enable-2fa auth-only
        

By completing these steps, you've successfully automated your release process, which will help in managing releases efficiently and transparently. Make sure to keep your documentation up-to-date with these configurations to aid your team or contributors in understanding the setup.

Vercel Setup Completion

Completing your Vercel setup involves linking your GitHub repository with Vercel using secrets for secure interactions and custom deployment settings. Follow these steps to integrate everything smoothly.

Configure GitHub Secrets for Vercel

  1. Retrieve Vercel Access Token

    • Generate an access token in Vercel to allow GitHub to securely interact with your Vercel account. Follow the instructions here: Create Vercel API Access Token.
  2. Install and Login to Vercel CLI

    • Install the Vercel CLI if not already installed, and log in:
      npm install -g vercel
      vercel login
      
  3. Link Your Project with Vercel

    • Navigate to your project directory and link your project to Vercel:
      vercel link
      
    • This command creates a .vercel directory in your project with a project.json file containing project and organization IDs.
  4. Extract Project and Organization IDs

    • Open the project.json in the .vercel directory and note the projectId and orgId.
  5. Add Secrets to GitHub

    • Go to your GitHub repository’s settings, navigate to 'Secrets', and add the following:
      • VERCEL_TOKEN: Your Vercel access token.
      • VERCEL_ORG_ID: The organization ID from Vercel.
      • VERCEL_PROJECT_ID: The project ID from Vercel.

Setup Deployment Configurations

To manage deployments effectively, especially to differentiate between production and preview deployments, it's essential to configure your deployment triggers and settings.

  1. Add Vercel Configuration in Repository
    • To prevent double deployment triggers (once from Vercel’s GitHub integration and once from your CI pipeline), create or update a vercel.json file in your repository with the following content:
      {
        "git": {
          "deploymentEnabled": {
            "main": false
          }
        }
      }
    • This configuration disables direct Vercel deployments on pushes to the main branch, allowing your CI process to handle it instead.

By completing these steps, your project is fully integrated with Vercel, leveraging GitHub Actions for CI/CD while keeping Vercel for actual deployments. This setup ensures that all changes pushed to your repository are automatically built and deployed in a secure and controlled manner.

Your project is now set up for continuous integration and delivery with Vercel and GitHub, supporting efficient development workflows and robust deployment strategies.

Setup CI (GitHub Actions)

Setting up a Continuous Integration (CI) pipeline with GitHub Actions is a great way to automate your release process. Here’s how to set up a CI pipeline for automatic semantic releases:

  1. Create GitHub Actions Workflow File

    • Run these commands in your terminal to create the necessary directories and workflow file:
      mkdir -p .github/workflows && touch .github/workflows/preview.yml && touch .github/workflows/production.yml
      
  2. Configure GitHub Actions Workflow

    • Paste the following configuration into your .github/workflows/production.yml file:

      name: GitHub Actions Vercel Production Deployment
      env:
        VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
        VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
      on:
        push:
          branches:
            - main
        permissions:
        contents: read
        jobs:
        deploy-production:
        name: Production Deployment
        runs-on: ubuntu-latest
        permissions:
        contents: write # to be able to publish a GitHub release
        issues: write # to be able to comment on released issues
        pull-requests: write # to be able to comment on released pull requests
        id-token: write # to enable use of OIDC for npm provenance
        steps: - name: Checkout
        uses: actions/checkout@v3
        with:
        fetch-depth: 0
              - name: Setup Node.js
                uses: actions/setup-node@v3
                with:
                  node-version: 'lts/*'
                  cache: 'yarn'
              - name: Clear Yarn Cache
                run: yarn cache clean
              - name: Install dependencies
                run: yarn install --frozen-lockfile
              - name: Create Release
                env:
                  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
                  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
                run: npx semantic-release
              - name: Install Vercel CLI
                run: yarn global add vercel@latest
              - name: Pull Vercel Environment Information
                run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
              - name: Build Project Artifacts
                run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
              - name: Deploy Project Artifacts to Vercel
                run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}

    and preview.yml

    name: GitHub Actions Vercel Preview Deployment
    env:
      VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
      VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
    on:
      push:
        branches-ignore:
          - main
    permissions:
      contents: read
    jobs:
      deploy-preview:
        name: Preview Deployment
        runs-on: ubuntu-latest
        permissions:
          contents: write # to be able to publish a GitHub release
          issues: write # to be able to comment on released issues
          pull-requests: write # to be able to comment on released pull requests
          id-token: write # to enable use of OIDC for npm provenance
        steps:
          - name: Checkout
            uses: actions/checkout@v3
            with:
              fetch-depth: 0
          - name: Setup Node.js
            uses: actions/setup-node@v3
            with:
              node-version: "lts/*"
              cache: "yarn"
          - name: Clear Yarn Cache
            run: yarn cache clean
          - name: Install dependencies
            run: yarn install --frozen-lockfile
          - name: Install Vercel CLI
            run: yarn global add vercel@latest
          - name: Pull Vercel Environment Information
            run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
          - name: Build Project Artifacts
            run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
          - name: Deploy Project Artifacts to Vercel
            run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}
  3. Dry-run the CI

    • Copy the release workflow file for a dry run:
      cp .github/workflows/release.yml .github/workflows/release-dry-run.yml
      
    • Modify the dry run file by changing the name to Release Dry-run and adding --dry-run to the semantic-release command.
  4. Prepare the package.json

    • Add "private": true, to your package.json to prevent accidental publishing to npm.
    • Include the following configuration to disable npm publishing in the package.json:
      "release": {
        "plugins": [
          [
            "@semantic-release/npm",
            {
              "npmPublish": false
            }
          ]
        ]
      }
    • If necessary, regenerate your yarn.lock by removing the existing one and running yarn install again.
  5. Push the Setup to GitHub

    • Use Commitizen to commit your changes:
      npx cz
      
    • Choose "chore" and enter the message: "add semantic-release configuration".
  6. Manually Run the Dry-run Workflow

    • Go to https://github.com/benloeffel/example/actions and manually trigger the dry-run workflow to ensure everything is configured correctly.

Setup Application Components and Styles

This part of the setup involves creating the necessary components and styles for your application. These files will form the basis of your app's structure and appearance.

  1. Create Application Files

    • Start by creating directories and initial React component files:
      mkdir -p src/app/\(app\) && cd src/app/\(app\) && touch layout.tsx page.tsx globals.scss
      
  2. Add Layout Component

    • Open layout.tsx and paste the following React component code. This component will serve as the basic layout for your application:

      import React from "react";
      import "./globals.scss";
      
      /* Our app sits here to not cause any conflicts with payload's root layout */
      const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
        return (
          <html>
            <body>
              <main>{children}</main>
            </body>
          </html>
        );
      };
      
      export default Layout;
  3. Add Page Component

    • Open page.tsx and input the following code. This page component includes some demo content and links, which illustrate how to use PayloadCMS with Next.js:

      import Example from "@/components/Example";
      import Link from "next/link";
      import React from "react";
      
      const Page = () => {
        return (
          <article className={["container"].filter(Boolean).join(" ")}>
            <h1>
              Payload 3.0 <span className="rainbow">BETA</span>!
            </h1>
            <p>
              This BETA is rapidly evolving, you can report any bugs against{" "}
              <a
                href="https://github.com/payloadcms/payload-3.0-demo/issues"
                target="_blank"
              >
                the repo
              </a>{" "}
              or in the{" "}
              <a
                href="https://discord.com/channels/967097582721572934/1215659716538273832"
                target="_blank"
              >
                dedicated channel in Discord
              </a>
              .
            </p>
      
            <p>
              <strong>
                Payload is running at <Link href="/admin">/admin</Link>
              </strong>
            </p>
      
            <p>
              <Link href="/my-route" target="_blank">
                /my-route
              </Link>{" "}
              contains an example of a custom route running the Local API.
            </p>
      
            <p>You can use the Local API in your server components like this:</p>
            <pre>
              <code>
                {`import { getPayload } from 'payload'
      import configPromise from "@payload-config";
      const payload = await getPayload({ config: configPromise })
      
      const data = await payload.find({
        collection: 'posts',
      })`}
              </code>
            </pre>
          </article>
        );
      };
      
      export default Page;
  4. Add Global Styles

    • Now, add the following CSS to globals.scss to style your application. These styles include a custom rainbow text effect:

      html,
      body {
        font-family: "Roboto", "Inter", sans-serif;
      }
      
      .container {
        max-width: 37.5rem;
        padding: 0 2rem;
        margin-left: auto;
        margin-right: auto;
      }
      
      h1 {
        font-size: 4rem;
      }
      
      .rainbow {
        font-family: monospace;
        letter-spacing: 5px;
        background: linear-gradient(
          to right,
          #6666ff,
          #0099ff,
          #00ff00,
          #ff3399,
          #6666ff
        );
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
        animation: rainbow_animation 6s ease-in-out infinite;
        background-size: 400% 100%;
      }
      
      @keyframes rainbow_animation {
        0%,
        100% {
          background-position: 0 0;
        }
      
        50% {
          background-position: 100% 0;
        }
      }
  5. Start the Application

    • Navigate back to the root directory and start the application with yarn dev. Ensure it spins up without issues.
  6. Commit and Release

    • Once your app is functional and the files are created, commit them using npx cz. Choose "feat" as the type and add "add initial layout and page file" as

Add Release Notes to Documentation

Automating the creation of release notes and changelogs can significantly improve the maintainability and transparency of your project. Here's how to configure your project to automatically generate and update a changelog with each release:

  1. Install Necessary Packages

    • Add the required Semantic Release plugins to your project:
      yarn add -D @semantic-release/changelog @semantic-release/git
      
  2. Configure Semantic Release for Changelogs

    • Update your package.json to include the changelog plugin configurations. Add the following to your existing Semantic Release configuration:
      "release": {
        "plugins": [
          "@semantic-release/github",
          "@semantic-release/release-notes-generator",
          [
            "@semantic-release/npm",
            {
              "npmPublish": false
            }
          ],
          [
            "@semantic-release/changelog",
            {
              "changelogFile": "CHANGELOG.md"
            }
          ],
          [
            "@semantic-release/git",
            {
              "assets": ["CHANGELOG.md"]
            }
          ]
        ]
      }
  3. Commit Changes with a Breaking Change Note

    • Commit these changes to your repository. Use a semantic commit message that includes a breaking change note to ensure a new release is triggered:
      git add .
      npx cz
      
    • When prompted by Commitizen, select "feat" for the type of change, and use the message "add changelog automation". Be sure to indicate that this is a breaking change when prompted.
  4. Run the Release Workflow

    • Push your changes and navigate to your GitHub Actions page to run the release workflow:
      git push
      
    • Go to https://github.com/benloeffel/example/actions and manually trigger the release workflow if necessary.
  5. Verify the Release

    • Confirm that the release was successful and that the CHANGELOG.md was updated and included in the release notes on GitHub.

By following these steps, your project now automatically generates a changelog with each release, documenting all changes in a standardized format. This not only saves time but also provides clear documentation for users and contributors about what changes have been made in each version of the project.

Import Project into Vercel

Deploying your project with Vercel ensures that your application is up and running on a robust, scalable cloud platform. Here's how to import and deploy your project on Vercel:

  1. Log In to Vercel

  2. Import Project from GitHub

    • Click on the "New Project" button and choose to import a project from GitHub. Follow the prompts to locate and select your repository.
  3. Configure Project Settings

    • Give your project a name that corresponds with its purpose or identity within Vercel.
  4. Set Environment Variables

    • Enter any necessary environment variables required for your project. These could include API keys, database URLs, or custom configuration values that should not be hard-coded in your project code.
  5. Deploy Your Project

    • Click the "Deploy" button to start the deployment process. Vercel will automatically build and deploy your project based on the settings defined in your package.json or other configuration files.
  6. Monitor Deployment

    • Wait for the deployment to complete. You can monitor the progress directly on the Vercel dashboard where the status of your build and deployment will be displayed.
  7. Verify Deployment

    • Once the deployment is complete, check the provided Vercel URL to ensure everything is working as expected. Test the deployed application to confirm that all functionalities are operational.

By completing these steps, your project is now live on Vercel! You're ready to share your application with the world or move forward to additional steps like custom domain configuration if necessary.

Setup Custom Domain

Customizing the domain for your project adds professionalism and branding. Vercel provides multiple options for linking your custom domain to your deployed projects. Here's how you can set it up:

Options for Custom Domain Setup

  1. Purchase Domain via Vercel

    • If you don't already own a domain, you can purchase one directly from Vercel. This integration allows for seamless management and configuration directly within your Vercel dashboard.
  2. Transfer Domain to Vercel

    • If your domain is registered with another provider and you prefer to manage everything in one place, you can transfer it to Vercel. This method also simplifies DNS management and ensures better compatibility with Vercel's features.
  3. Point Domain to Vercel Servers via A Record

    • If you prefer to keep your domain registered with an external provider, you can point it to Vercel's servers using A records. This method is less flexible than using Vercel's nameservers because it doesn’t support root domains with CNAME records, which are required for some of Vercel’s functionalities.
  4. Point Domain to Vercel's Nameservers

    • Vercel recommends using their nameservers. This approach not only simplifies setup but also enhances features like automatic SSL and preview deployments. Point your domain's DNS settings to Vercel’s nameservers from your domain registrar’s control panel.

Implementation Steps

  • Log In to Vercel and Navigate to Your Project

    • Go to your project’s dashboard on Vercel.
  • Add Your Custom Domain

    • Navigate to the 'Settings' tab, find the 'Domains' section, and click 'Add'.
    • Enter your domain name and follow the on-screen instructions to verify ownership.
  • Configure DNS Settings

    • Depending on the option you chose:
      • For nameserver pointing, change your domain's nameservers to the ones provided by Vercel.
      • For A record pointing, add the A records as specified by Vercel during the setup.
  • Verify Domain Configuration

    • Once configured, Vercel automatically checks and verifies the DNS settings. This process might take some time as DNS changes need to propagate.
  • SSL and Deployment

    • Vercel automatically provisions an SSL certificate for your domain and makes your site accessible via HTTPS.

Additional Notes

  • Preview Deployments
    • Vercel’s nameserver option supports preview deployments, which is ideal for testing changes in a production-like environment before going live. If using A records and you need preview deployments, follow the guide here: Preview Deployment Suffix without Vercel Nameservers.

By setting up your custom domain on Vercel, you ensure that your project maintains a professional appearance and is accessible under your brand. Choose the method that best suits your operational style and needs.

Modern Web Application Guide (Next.js & PayloadCMS on GitHub and Vercel)

Create a MongoDB database

  1. Go to https://account.mongodb.com/account/login and login
  2. Once logged in, create a new project.
  3. Give the project a name
  4. Give the project a tag like key environment and value production
  5. Click on "Next"
  6. Add a amember and set permissions or select an existing member.
  7. Proceed with clicking on "Create Project"
  8. Once the project has been created, click on the "Create" button to create a deployment
  9. Select the free "M0" database cluster
  10. Give the cluster a suitable name such as prod-example-app
  11. Uncheck "Add a sample dataset"
  12. Choose the provider like AWS and Region like Frankfurt
  13. Give the project a tag like key environment and value production
  14. Click on Create Deployment Button
  15. Create a database username like example-user and auto generate a secure password. Save these credentials in your password manager.
  16. Once the database deployment has been created click on the "connect" button followed by "Drivers"
  17. Copy the connection string and store it somewhere for later: mongodb+srv://example-user:<password>@prod-example-app.1xxerno.mongodb.net/?retryWrites=true&w=majority&appName=prod-example-app
  18. Network access needs to be open so Anywhere since Vercel uses a Dynamic IP address.

Create a GitHub project

  1. Login at [https://github.com/]
  2. Click on "New repository"
  3. Provide a repository name such as "example-app"
  4. Make the project private
  5. Click on "Create repository"
  6. Copy the repositories ssh string like: git@github.com:benloeffel/example.git

Initial setup

  1. Create a new directory mkdir example-directory && cd example-directory
  2. Type git clone git@github.com:benloeffel/example.git .
  3. Create a payloadcms application with npx create-payload-app@beta
  4. Provide a project name like "example"
  5. Choose a project template like "blank-3.0"
  6. Select a database (MongoDB or Postgres).
  7. Enter your MongoDB connection string of earlier and press enter
  8. Wait for the dependencies to install
  9. Type cd example && mv * ../ && mv .* ../ && cd .. && rmdir example
  10. Run the application with yarn dev or follow directions in README.md
  11. If everything is working, run git add . && git commit -m "initial commit" && git push to run the initial commit.

Setup Conventional Commits

  1. Install CommitLint CLI yarn add -D @commitlint/cli
  2. Install CommitLint Conventional Rulesetyarn add -D @commitlint/config-conventional
  3. Create a CommitLint configuration file by running touch .commitlintrc && code .commitlintrc
  4. Paste the following configuration:
{
  "extends": ["@commitlint/config-conventional"],
  "rules": {
    "body-max-line-length": [1, "always", 200]
  }
}
  1. Commit with Commitlint git add . && git commit -m "chore: add commitlint" && git push

Setup Commitizen

  1. Install commitizen yarn add -D commitizen
  2. Install commitizen ruleset with npx commitizen init cz-conventional-changelog, this will add this section to our package.json file:
"config": {
  "commitizen": {
    "path": "./node_modules/cz-conventional-changelog"
  }
}
  1. Remove the automatically created package-lock.json that we don't need since we use yarn.lock
  2. . Create a commit with npx cz
  3. Choose "chore"
  4. Skip the optional scope
  5. Write "add commitizen" and hit enter
  6. Skip the long description
  7. Type "N" and press enter to the breaking changes question
  8. Type "N" and press enter to the affects open issues question
  9. Finally, push the changes with "git push"

Setup Husky to use Commitlint in Pre-Commit Hook

  1. Install husky and initialize it with npx husky-init && yarn install
  2. This create a pre-commit file we can delete as we're not using it
  3. Now create our own pre-commit file with npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
  4. This will create the file .husky/commit-msg with the following contents:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no -- commitlint --edit "$1"
  1. Let's test out if it works by running git add . && git commit -m "chore: add husky" && git push

Install semantic-release

  1. Install semantic-release yarn add -D semantic-release
  2. Install semantic-release cli and set it up yarn add -D semantic-release-cli && npx semantic-release-cli setup
  3. Choose if the repository is private, in this case "Y" and press enter.
  4. What is your npm registry, accept the default by pressing enter
  5. What is your username, enter your npm username and press enter.
  6. What is your passwrod, enter the password and press enter.
  7. What is your NPM two-factor authentication code, enter the code and press enter.
  8. Visit
  9. Check that permissions are only enabled for "repo".
  10. Set an expiration date of for example 30 days but note:

    For security reasons, the token should have an expiration date. But be aware that it can be confusing and frustrating, even expensive, when semantic-release suddenly stops working. It’s not so easy to dig out the reason when it’s the token being expired. Note this well in your project docs so others won’t need to spend too much time searching for the cause. Even better, create a recurring reminder to renew the token in time.

  11. Press generate token and copy the token ghp_lkNYvNHEOHb43QmkXXXXXXXXXXXXXXXXXXXX and pase it into the semantic-releases cli
  12. Select the CI to use, in our case that's GitHub Actions and Press Enter
  13. On GitHub check that the NPM_TOKEN is not shown in the repository secrets: https://github.com/benloeffel/example/settings/secrets/actions
  14. Set the following permissions for the fine-grained personal access tokens: Contents: read/write, Issues: read/write, Metadata: read
  15. Click on create token, and copy the token: github_pat_11ADXYIGI0cXZUv5VrAxl2_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX and pase it into the cli
  16. Login to npm using npm login --auth-type=legacy, and provide the username, password and one time password
  17. Since semantic-releases only supports the auth-only mode with 2FA, we need to enable it using: npm profile enable-2fa auth-only
  18. If you experience an error here and you already have set up 2FA for your npm account, set up 2FA again from scratch may help. Unset it first: npm profile disable-2fa and then enabling it again with npm profile enable-2fa auth-only

Setup CI (Github Actions)

  1. Create a release.yml with mkdir .github && mkdir .github/workflows && touch .github/workflows/production.yml && touch .github/workflows/preview.yml
  2. In the file pase the following configuration for GitHub Actions:
name: Release
on:
  push:
    branches:
      - main

permissions:
  contents: read

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    permissions:
      contents: write # to be able to publish a GitHub release
      issues: write # to be able to comment on released issues
      pull-requests: write # to be able to comment on released pull requests
      id-token: write # to enable use of OIDC for npm provenance
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 'lts/*'
      - name: Install dependencies
        run: yarn install --frozen-lockfile
      - name: Audit dependencies for security vulnerabilities
        run: yarn audit
      - name: Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npx semantic-release
  1. Let's dry-run the ci by first copying the file cp .github/workflows/release.yml .github/workflows/release-dry-run.yml
  2. In the dry-run file, replace the name: Release Dry-run and the run: npx semantic-release --dry-run
  3. Add "private": true, to the package.json
  4. To ensure that we're not releasing to npm add the following to the package.json, it may be required to remove the yarn.lock and create it again with yarn install
"release": {
  //...
  "plugins": [
    [
      "@semantic-release/npm",
      {
        "npmPublish": false
      }
    ]
  ]
}
  1. Push the changes to main. npx cz, select "chore" and message: "add semantic-releases"
  2. Now navigate to https://github.com/benloeffel/example/actions and manually run our dry-run workflow. If everything worked fine, we can create the first release.
  3. Before we release, let's create our app mkdir src/app/\(app\) && cd src/app/\(app\) && touch layout.tsx page.tsx globals.scss
  4. Add this to the layout.tsx
import React from 'react'
import './globals.scss'

/* Our app sits here to not cause any conflicts with payload's root layout  */
const Layout: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return (
    <html>
      <body>
        <main>{children}</main>
      </body>
    </html>
  )
}

export default Layout
  1. Add this to the page.tsx
import Example from '@/components/Example'
import Link from 'next/link'
import React from 'react'

const Page = () => {
  return (
    <article className={['container'].filter(Boolean).join(' ')}>
      <h1>
        Payload 3.0 <span className="rainbow">BETA</span>!
      </h1>
      <p>
        This BETA is rapidly evolving, you can report any bugs against{' '}
        <a href="https://github.com/payloadcms/payload-3.0-demo/issues" target="_blank">
          the repo
        </a>{' '}
        or in the{' '}
        <a
          href="https://discord.com/channels/967097582721572934/1215659716538273832"
          target="_blank"
        >
          dedicated channel in Discord
        </a>
        .
      </p>

      <p>
        <strong>
          Payload is running at <Link href="/admin">/admin</Link>
        </strong>
      </p>

      <p>
        <Link href="/my-route" target="_blank">
          /my-route
        </Link>{' '}
        contains an example of a custom route running the Local API.
      </p>

      <p>You can use the Local API in your server components like this:</p>
      <pre>
        <code>
          {`import { getPayload } from 'payload'
import configPromise from "@payload-config";
const payload = await getPayload({ config: configPromise })

const data = await payload.find({
  collection: 'posts',
})`}
        </code>
      </pre>
    </article>
  )
}

export default Page
  1. Add this to the globals.scss
html,
body {
  font-family: 'Roboto', 'Inter', sans-serif;
}

.container {
  max-width: 37.5rem;
  padding: 0 2rem;
  margin-left: auto;
  margin-right: auto;
}

h1 {
  font-size: 4rem;
}

.rainbow {
  font-family: monospace;
  letter-spacing: 5px;
  background: linear-gradient(to right, #6666ff, #0099ff, #00ff00, #ff3399, #6666ff);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: rainbow_animation 6s ease-in-out infinite;
  background-size: 400% 100%;
}

@keyframes rainbow_animation {
  0%,
  100% {
    background-position: 0 0;
  }

  50% {
    background-position: 100% 0;
  }
}
  1. Start the application with yarn dev, if it spins up without issues you can commit with npx cz and choose "feat" with the text "add initial layout and page file. You need to mark this as a breaking change otherwise there won't be a release, simply a tag.
  2. Once that's done we can manually execute out release job and watch the magic happen.

Import Project into Vercel

  1. Login to Vercel
  2. Import Project via Github and select the project to import
  3. Give the project a name
  4. Pase in the environment variables
  5. Press deploy
  6. Wait for the deployment to complete
  7. Once the deployment is complete and everything is working correctly we can move onto the domain part.

Setup Custom Domain

Setup of a custom domain we can choose if we want to:

  • Purchase the domain directly via Vercel
  • Transfer the domain from external to Vercel
  • Leave the domain external and point to Vercel Servers via A record
  • Leave the domain external and point to Vercels Nameservers

It's important to note that Vercel prefers the nameserver approach so it's easy to create preview deployments. If thats not possible, apparently there is a workaround: https://vercel.com/guides/preview-deployment-suffix-without-vercel-nameservers

VERCEL SETUP

Finally, let’s add the required values from Vercel as secrets in GitHub:

  1. Retrieve your Vercel Access Token
  2. Install the Vercel CLI and run vercel login
  3. Inside your folder, run vercel link to create a new Vercel project
  4. Inside the generated .vercel folder, save the projectId and orgId from the project.json
  5. Inside GitHub, add VERCEL_TOKEN, VERCEL_ORG_ID, and VERCEL_PROJECT_ID as secrets.

To setup Vercel with preview and production deployments we need the following details: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} -> YPPQDdLDmHCULxBFFOLaVFtF VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} -> prj_l4AznSpYJmnYYoilYjYIjnAoO7dH VERCEL_TOKEN: ${{secrets.VERCEL_TOKEN}} -> 7Hy7xxMqfn3x0P9DMXYAe7Tr (How to create a token: https://vercel.com/guides/how-do-i-use-a-vercel-api-access-token)

You can find the org and project IDs in the project.json file in the .vercel folder of your local project.

OR

Your "Org ID" is also called your user ID, and it's found at vercel.com/account > settings > general -- at the bottom Your "Project ID" is found at vercel.com/dashboard > your project name > settings > general -- at the bottom

To prevent pushing main branch twice, once via vercel auto deployment and once via the semantic-release bot add a vercel.json

{
    "git": {
        "deploymentEnabled": {
            "main": false
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment