WebOps

Design & Strategy

We start with your goals and how your team works, then design the platform to match.

Website Builds

Custom Drupal, WordPress, and headless builds that perform from day one and stay easy to run.

Migrations

High-stakes CMS migrations from virtually any source onto a platform we support, with content and uptime protected.

Maintenance & Support

Proactive, senior-led care that keeps your platform secure, fast, and ready for what comes next.

AI Integration

Practical, native AI features built by the team contributing to Drupal’s AI core.

WebOps Audits

A clear, prioritized picture of your platform’s health and exactly what to fix first.

RevOps

CRM Implementation

HubSpot implementation built around how your team sells. We scope what is actually needed, configure what your team can operate, and hand off a system that works on day one.

CRM Migrations

Marketo, Eloqua, Pardot, and Salesforce moves into HubSpot. We treat every migration as a risk mitigation project, because for the VP who owns the pipeline, it is.

CRM Architecture

The structural decisions that shape everything downstream: object relationships, data governance, integration strategy, and managed data migration. Designed for how your team actually works.

Insights

Articles

Practical thinking on WebOps, RevOps, and running platforms that cannot fail.

Newsletter

Occasional, useful notes from the people doing the work. No noise.

Events & Talks

Where to find our team, from DrupalCon to industry meetups and webinars.

Our Work

About

Our Story

Why Digital Polygon exists, and the through-line behind every engagement.

Team & Leadership

The senior, global team you actually work with, named and accountable.

Careers

Join a senior team that builds the platforms and revenue systems people depend on.

Open Source

The modules we maintain, the initiatives we lead, and Polymer, our WebOps product.

, ,

Introduction to Headless Drupal + Next.js

A full walkthrough on setting up your headless Drupal content management system (CMS) with a Next.js frontend.

Introduction to Headless Drupal + Next.js

Headless architecture is gaining popularity and at Digital Polygon we decided to explore it by relaunching www.digitalpolygon.com with a modern headless architecture. Today, I’m going to share the experience and lessons we learned.

What is Headless?

A body without a head is considered headless by definition. I like to put it in a different light: a body capable of wielding numerous heads. The OTT platforms are an excellent illustration of how headless works. We begin viewing a movie on a website and can continue watching it on a mobile app. That is the power of headlessness. Multiple targets are served by a single source of information. One body with the ability to wield numerous heads.

A headless architecture in the web refers to a back-end system that exposes data via APIs that may be accessed by other platforms. There are several classic content management systems (CMS) available for managing a website’s content. We chose Drupal for its flexibility and scalability.

What is headless Drupal?

Drupal without its front-end layer. In other words, Drupal is used as a back-end content repository. The front-end can be served by any of latest technologies. We chose Next.js as our front-end stack for www.digitalpolygon.com.

Diagram of Headless Drupal

In this article, I’m going to cover

  • How to setup headless Drupal with DDEV
  • How to setup Next.js front-end using DDEV
  • How to connect Next.js with Drupal

First thing’s first, pick a solid starter kit that will make your task simple. Both Chapter Three and Pantheon did some incredible work to construct some starter kits:

  1. Pantheon Decoupled Kit Next Drupal Starter on GitHub
  2. Chapter Three Next.js for Drupal Quick Start

To rebuild www.digitalpolygon.com, we decided to use Pantheon’s Next Drupal Starter, which includes integration for Lando. Although the Lando integration is excellent, we integrated DDEV into the starter kit because it is our team’s preferred local development tool.

To set up Drupal you can follow this DDEV quick start guide.

Before proceeding further, make sure you have a working Drupal instance at – https://drupal-starter.ddev.site/

Let’s go on to the exciting part, which is configuring the Next.JS with DDEV.

Setup Next.js Front-end with DDEV

These instructions presume that you have installed DDEV locally and have copied Pantheon’s starter kit to a folder called “next-drupal-starter.”

  1. Go to your front-end application directory i.e. cd next-drupal-starter
  2. Run ddev config
    • Enter project name
    • Enter docroot location
    • Enter php as your project type. At the time of writing this blog, DDEV doesn’t support any other project type.
  3. This will install DDEV in your project
  4. Next, edit config.yaml file location in .ddev directory and update the following:
    • Set omit_containers: ['db', 'dba']
      • We don’t need database containers because databases will be managed with Drupal BE.
    • Set disable_settings_management to true
      • We don’t need Drupal settings here.

At the end of above steps your config.yaml file should look like this

name: next-drupal-starter
type: php
docroot: ""
php_version: "7.4"
webserver_type: nginx-fpm
router_http_port: "80"
router_https_port: "443"
xdebug_enabled: false
additional_fqdns: []
nfs_mount_enabled: false
mutagen_enabled: false
use_dns_when_possible: true
composer_version: "2"
web_environment: []
nodejs_version: "16"
omit_containers: ['db', 'dba']
disable_settings_management: true

Ok, so far so good, you have setup DDEV containers but your application isn’t running yet. To get a functioning application, we must take a few additional steps.

  1. By default, Next.js runs on port 3000, so we must map port 80 of the local machine to port 3000 of the DDEV web container. There are several options.
    • Port mapping can be done using docker-compose.*.yaml as per this example
    • In nginx, create a virtual host. Since we require more than just port mapping, we are employing the vhost technique.

Make the following changes to the next-drupal-starter.conf file located in the .ddev/nginx_full directory.

server {
   server_name next-drupal-starter.ddev.site;
   listen 80;
   location / {
       proxy_set_header   X-Forwarded-For $remote_addr;
       proxy_http_version 1.1;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "Upgrade";
       proxy_set_header Host $http_host;
       proxy_pass http://127.0.0.1:3000;
   }
}
  1. Restart DDEV
  2. We’re not quite there yet, but at this time you will have a working Next.js instance. To see your site, execute the ddev yarn dev command
  3. You may now access the website at http://next-drupal-starter.ddev.site/

You can’t close the terminal since we need to manually run ddev yarn dev. We want it to operate in the background to correct this. We’ll check the pm2 package.

Since it’s a node package we will have to update our docker image to include this package. To do this

  1. Create a DockerFile in the .ddev/web-build directory with following content:
# You can copy this Dockerfile.example to Dockerfile to add configuration
# or packages or anything else to your webimage
  ARG BASE_IMAGE
  FROM $BASE_IMAGE
  RUN npm install --global pm2
  1. After installing pm2, we need to run the Next.js js application using pm2. DDEV provides hooks to execute commands after defined actions. So, we will use the post-start hook. Update .ddev/config.yml with below
hooks:

    post-start:

      - exec: yarn install

      - exec: pm2 start "yarn dev"
  1. Restart DDEV
  2. Visit http://next-drupal-starter.ddev.site/

Both the front-end and the back-end applications should now be operating in their isolated DDEV containers. We must create a connection between the front-end and back-end web containers so our front-end application can communicate with the back-end in order to access APIs.

Let’s create a custom Docker compose file to establish a link. Create a .ddev/docker-compose.connect-drupal.yaml in the front-end application with the following content:

version: '3.6'

services:

  web:

    external_links:

      - ddev-router:drupal-starter.ddev.site

Congratulations, after this front-end DDEV setup is complete!

Let’s configure Drupal to be headless.

Back-end Drupal Setup for Decoupled

Headless Profile

Install the Pantheon Decoupled Profile

  • This will install Pantheon Decoupled which will create a preview site and oAuth consumer.
    • Preview site can be used to preview your changes i.e. how your changes would look in front-end
    • oAuth consumer will be used to connect front-end with back-end.

Oauth Consumer

You can either utilize the current oAuth client given by above profile, or make another one. This consumer is used in API calls from Next.js to Drupal.

To create a new consumer

  • Go to /admin/config/services/consumer/add
  • Enter
    • Label
    • User
    • Secret
    • Scope
  • Save the consumer

Make sure to note the UUID & Secret of the above entity. They will be used in front-end configurations.

Preview Site

Similar to oAuth customers, you can choose to use an example preview site created by the above decoupled profile. Alternatively, you can also create a new preview site

To create a new site:

Please make sure to note the secret. It will be used in front-end configurations.

After configuring Drupal for decoupled applications, the final step is connecting the front-end with the back-end.

Connect Next.js with Drupal Back-end

  • Goto your front-end application root
  • You will see a .env.example file
  • Copy it to .env.development.local and update following values:
  BACKEND_URL= https://drupal-starter.ddev.site
  IMAGE_DOMAIN= drupal-starter.ddev.site
  # Used to set the debug mode for the DrupalState store(s)
  # If not set, debug mode for the store(s) is set to false
  DEBUG_MODE=
  # this value can also be set in the command line
  # before running commands for example
  # FRONTEND_URL=example.com npm run build
  FRONTEND_URL=  https://next-drupal-starter.ddev.site
  # These variables are needed to enable Preview
  PREVIEW_SECRET= Use secret from preview site configuration
  CLIENT_ID= Use UUID of oAuth consumer created
  CLIENT_SECRET= Use Secret of oAuth consumer created

Visit Pantheon Decoupled Kit Next Drupal Starter for more information.

After configuring above environment variables. Run `ddev restart` in the front-end application.

And Ta-da! Both of your sites are ready, and are talking to each other.

Keep reading

More from the field.

For projects that cannot fail

When it has to work. We deliver.

Tell us what you are working on. We will tell you honestly whether we are the right fit, and what a strong engagement looks like.