Deploy Next.js and Drupal on Platform.sh

Contribute to the Platform.sh knowledge base, or check out our resources

Join our community       Documentation       Blog       Report a bug       Request a feature

Open issues    Open PRs    License   




Contents

About this project

This template demonstrates a multi-app deployment on Platform.sh, in this case, a Next.js frontend consuming data from a Drupal 9 backend running on the same environment. It is based largely on the configuration instructions provided by the Next-Drupal project by Chapter Three.

Next.js is an open-source web framework written for Javascript, and Drupal is a flexible and extensible PHP-based CMS framework..

Features

  • PHP 8.1
  • Node.js 16
  • MariaDB 10.4
  • Redis 6.0
  • Network Storage
  • Automatic TLS certificates
  • Multi-app configuration
  • yarn-based builds
  • Delayed SSG build (post deploy hook)

Getting started

Deploy

Quickstart

The quickest way to deploy this template on Platform.sh is by clicking the button below. This will automatically create a new project and initialize the repository for you.

Deploy on Platform.sh

Note:

If you do not already have a Platform.sh account, you will be asked to fill out some basic information, after which you will be given a 30-day free trial to experiment with our platform.

Other deployment options

Deploy directly to Platform.sh from the command line
  1. Clone this repository:

    git clone https://github.com/platformsh-templates/nextjs-drupal
  2. Create a free trial:

    Register for a 30 day free trial with Platform.sh. When you have completed signup, select the Create from scratch project option. Give you project a name, and select a region where you would like it to be deployed. As for the Production environment option, make sure to match it to this repository's settings, or to what you have updated the default branch to locally.

  3. Install the Platform.sh CLI

    Linux/OSX

    curl -sS https://platform.sh/cli/installer | php

    Windows

    curl -f https://platform.sh/cli/installer -o cli-installer.php
    php cli-installer.php

    You can verify the installation by logging in (platformsh login) and listing your projects (platform project:list).

  4. Set the project remote

    Find your PROJECT_ID by running the command platform project:list

    +---------------+------------------------------------+------------------+---------------------------------+
    | ID            | Title                              | Region           | Organization                    |
    +---------------+------------------------------------+------------------+---------------------------------+
    | PROJECT_ID    | Your Project Name                  | xx-5.platform.sh | your-username                   |
    +---------------+------------------------------------+------------------+---------------------------------+

    Then from within your local copy, run the command platform project:set-remote PROJECT_ID.

  5. Push

    git push platform DEFAULT_BRANCH
Deploy from GitHub

If you would instead to deploy this template from your own repository on GitHub, you can do so through the following steps.

Note:

You can find the full GitHub integration documentation here.

  1. Clone this repository:

    Click the Use this template button at the top of this page to create a new repository in your namespace containing this demo. Then you can clone a copy of it locally with git clone git@github.com:YOUR_NAMESPACE/nextjs-drupal.git.

  2. Create a free trial:

    Register for a 30 day free trial with Platform.sh. When you have completed signup, select the Create from scratch project option. Give you project a name, and select a region where you would like it to be deployed. As for the Production environment option, make sure to match it to whatever you have set at https://YOUR_NAMESPACE/nextjs-drupal.

  3. Install the Platform.sh CLI

    Linux/OSX

    curl -sS https://platform.sh/cli/installer | php

    Windows

    curl -f https://platform.sh/cli/installer -o cli-installer.php
    php cli-installer.php

    You can verify the installation by logging in (platformsh login) and listing your projects (platform project:list).

  4. Setup the integration:

    Consult the GitHub integration documentation to finish connecting your repository to a project on Platform.sh. You will need to create an Access token on GitHub to do so.

Deploy from GitLab

If you would instead to deploy this template from your own repository on GitLab, you can do so through the following steps.

Note:

You can find the full GitLab integration documentation here.

  1. Clone this repository:

    git clone https://github.com/platformsh-templates/nextjs-drupal
  2. Create a free trial:

    Register for a 30 day free trial with Platform.sh. When you have completed signup, select the Create from scratch project option. Give you project a name, and select a region where you would like it to be deployed. As for the Production environment option, make sure to match it to this repository's settings, or to what you have updated the default branch to locally.

  3. Install the Platform.sh CLI

    Linux/OSX

    curl -sS https://platform.sh/cli/installer | php

    Windows

    curl -f https://platform.sh/cli/installer -o cli-installer.php
    php cli-installer.php

    You can verify the installation by logging in (platformsh login) and listing your projects (platform project:list).

  4. Create the repository

    Create a new repository on GitLab, set it as a new remote for your local copy, and push to the default branch.

  5. Setup the integration:

    Consult the GitLab integration documentation to finish connecting a repository to a project on Platform.sh. You will need to create an Access token on GitLab to do so.

Deploy from Bitbucket

If you would instead to deploy this template from your own repository on Bitbucket, you can do so through the following steps.

Note:

You can find the full Bitbucket integration documentation here.

  1. Clone this repository:

    git clone https://github.com/platformsh-templates/nextjs-drupal
  2. Create a free trial:

    Register for a 30 day free trial with Platform.sh. When you have completed signup, select the Create from scratch project option. Give you project a name, and select a region where you would like it to be deployed. As for the Production environment option, make sure to match it to this repository's settings, or to what you have updated the default branch to locally.

  3. Install the Platform.sh CLI

    Linux/OSX

    curl -sS https://platform.sh/cli/installer | php

    Windows

    curl -f https://platform.sh/cli/installer -o cli-installer.php
    php cli-installer.php

    You can verify the installation by logging in (platformsh login) and listing your projects (platform project:list).

  4. Create the repository

    Create a new repository on Bitbucket, set it as a new remote for your local copy, and push to the default branch.

  5. Setup the integration:

    Consult the Bitbucket integration documentation to finish connecting a repository to a project on Platform.sh. You will need to create an Access token on Bitbucket to do so.

Post-install instructions

There are two steps you will need to execute in order to complete the demo template run for the first deploy.

1. Update Drupal credentials

This demo repository is set up to deploy both front and backend application containers to the production environment, and to initialize the database with files and data generated by a collection of scripts that run during Drupal's first deploy.

When the project is initialized, a set of initial administrator credentials were used to install Drupal. In this case, the slug of the first commit event was used as the password. This is important because this information is only available during this first commit. After you've deployed the demo, view the first activity for the production environment, and find this block of text when Drupal's deploy hook runs:

Creating environment pr-1
  Starting environment
  Opening applications nextjs, drupal, and their relationships
  Executing deploy hook for application drupal
    Created Drush configuration file: /app/.drush/drush.yml
    
    * Fresh project detected.
        ✔ Installing Drupal with a Standard profile (see https://next-drupal.org/learn/quick-start/install-drupal).
        ✔ Installation complete.
        ✔ Your Drupal site has been installed with the following credentials:
            * user: admin
            * pass: PASSWORD-GENERATED-HERE-ON-FIRST-PUSH
        ✗ WARNING: Update your password and email immediately. They will only be available once.

From this, you can log into Drupal using the credentials listed (admin/PASSWORD-GENERATED-HERE-ON-FIRST-PUSH) and then update them to something more memorable.

2. Rebuild the container

Platform.sh is secure by default. Part of that security involves read-only access to the file system and container isolation during the build process. Because of this, credentials for the frontend application were not yet available for the first Next.js build.

This will only be the case for this first deployment. The final post-install step is to add a build-visible environment variable to rebuilt and restart the Next.js container:

platform variable:create -p PROJECT_ID -e ENVIRONMENT -l environment --name DEPLOY --value FRIDAY --visible-build=true --prefix=env: -n

Once you have completed these steps, you will have a deployed Next.js container consuming data from a backend Drupal container on the same environment. You will be able to create a new environment that is an exact copy of production and start developing.

platform get PROJECT_ID
cd project-name
platform environment:branch updates

Local development

This section provides instructions for running the Next.js + Drupal template locally, connected to a live database instance on an active Platform.sh environment.

In all cases for developing with Platform.sh, it's important to develop on an isolated environment - do not connect to data on your production environment when developing locally. Each of the options below assume the following starting point:

platform get PROJECT_ID
cd project-name
platform environment:branch updates

Note:

For many of the steps below, you may need to include the CLI flags -p PROJECT_ID and -e ENVIRONMENT_ID if you are not in the project directory or if the environment is associated with an existing pull request.

Running the Drupal backend
  1. Using ddev:

    ddev provides an integration with Platform.sh that makes it simple to develop Drupal locally. Check the providers documentation for the most up-to-date information.

    In general, the steps are as follows:

    1. A configuration file has already been provided at api/.ddev/providers/platform.yaml, so you should not need to run ddev config.

    2. Retrieve an API token for your organization via the management console.

    3. Update your dedev global configuration file to use the token you've just retrieved:

      web_environment:
      - PLATFORMSH_CLI_TOKEN=abcdeyourtoken`
    4. Run ddev restart.

    5. Get your project ID with platform project:info. If you have not already connected your local repo with the project (as is the case with a source integration, by default), you can run platform project:list to locate the project ID, and platform project:set-remote PROJECT_ID to configure Platform.sh locally.

    6. Update the .ddev/providers/platform.yaml file for your current setup:

      environment_variables:
         project_id: PROJECT_ID
         environment: CURRENT_ENVIRONMENT
         application: drupal
    7. Get the current environment's data with ddev pull platform.

    8. When you have finished with your work, run ddev stop and ddev poweroff.

  2. Using Lando:

    Lando supports PHP applications configured to run on Platform.sh, and pulls from the same registry Platform.sh uses on your remote environments during your local builds through its own recipe and plugin.

    1. When you have finished with your work, run lando stop and lando poweroff.
Running the Next.js frontend

After you have created a new environment, you can connect to a backend Drupal instance and develop the frontend locally with the following steps.

  1. cd client

  2. Update the environment variables for the current environment by running ./get_local_config.sh. This will pull the generated .env.local file for the current environment.

    # This .env file is generated programmatically within the backend Drupal app for each Platform.sh environment
    # and stored within an network storage mount so it can be used locally.
    
    NEXT_PUBLIC_DRUPAL_BASE_URL=https://api.ENVIRONMENT-HASH-PROJECTID.REGION.platformsh.site
    NEXT_IMAGE_DOMAIN=api.ENVIRONMENT-HASH-PROJECTID.REGION.platformsh.site
    DRUPAL_SITE_ID=nextjs_site
    DRUPAL_FRONT_PAGE=/node
    DRUPAL_CLIENT_ID=CONSUMER_CLIENT_ID
    DRUPAL_CLIENT_SECRET=GENERATED_SECRET
  3. Install dependencies: yarn --frozen-lockfile.

  4. Run the development server: yarn dev. Next.js will then run on http://localhost:3000.

Customizations

The following changes have been made relative to the Next.js-Drupal documentation, nameley the Getting Started documentation, to run on Platform.sh. If using this project as a reference for your own existing project, replicate the changes below to your project.

Shared files
  • .platform/services.yaml, and .platform/routes.yaml files have been added. These provide Platform.sh-specific configuration for provisioning an Oracle MySQL container and for defining how traffic is handled between the two application containers, respectively. They are present in all projects on Platform.sh, and you may customize them as you see fit. Consult those files for more information, or take a look at the Routes and Services documentation for details about configuration.
Drupal (api)

Like the Next.js-Drupal documentation recommends, a starter Drupal 9 site is used initially with the command composer create-project drupal/recommended-project api. After that, a few files have been added to run the demonstration, to deploy on Platform.sh, and to maintain the Next.js-Drupal connection across development environments.

  • drush/platformsh_generate_drush_yaml.php: This file generates a Drush configuration file in the application container on every deployment.
  • api/.lando.upstream.yml: A default Lando configuration file has been added to make starting up locally with Lando easier. See the Local development section for more details.
  • api/web/sites/default/settings.platformsh.php: Contains Platform.sh-specific configuration, namely setting up the database connection to the MariaDB service and caching via Redis.
  • api/web/sites/default/settings.php: Has been modified to use the previous Platform.sh-specific settings file, plus modifications for local development with ddev.
  • A api/.platform.app.yaml file has been added, which is required to define the build and deploy process for all application containers on Platform.sh. Take a look at the Application documentation for more details about configuration.
  • .ddev: ddev local development configuration has been provided. See the Local development section for more details.

In addition, a number of extra files have been included in this template to support Next.js + Drupal connections across development environments on Platform.sh. All of those files can be found in the api/platformsh-scripts directory.

In most cases, you will be able to use most of the files included in that directory in your migration, but not all of them will be relevant since this template is intended to provide a "one-click" demo for Next.js-Drupal. See the Migrating section for more information.

Next.js customizations (client)

As outlined in the Next.js-Drupal documentation, the Next.js frontend application has been generated from the Chapter Three upstream using the npx create-next-app -e https://github.com/chapter-three/next-drupal-basic-starter command. The most important changes made to that starting point are listed below. You can replicate those changes to migrate your own Next.js frontend pulling data from Drupal.

  • sharp was added as a dependency, since it is recommended for handling images.
  • The upstream repo comes with a single start command (yarn preview) which is a combination of two commands (next build && next start). During deployment these commands need to be run separately, so the commands yarn build and yarn start have been added to package.json.
  • A client/.environment file has been added. This file is sourced on a Platform.sh environment during startup, at the beginning of the deploy hook, and whenever you SSH into the environment (platform ssh -e ENVIRONMENT_ID). It initializes environment variables specific to this demo, related to the Drupal backend URL and initial connection credentials.
  • A client/get_local_config.sh script has been added. This script simplies the local development process, by connecting to an active Platform.sh environment and retrieving the required .env.local file needed to run Next.js on your computer. See the Local development section for more details.
  • A client/.platform.app.yaml file has been added, which is required to define the build and deploy process for all application containers on Platform.sh. Because of how Platform.sh works, the Next.js build is delayed considerably to the post_deploy hook after the Drupal container has fully deployed and has begun serving its endpoints. Take a look at the Application documentation for more details about configuration.
  • client/platformsh-scripts/test/next-drupal-debug: Despite very detailed documentation provided from the Chapter Three team, developers often run into issues setting up the Next.js/Drupal connection for the first time. The problem is made more difficult on Platform.sh, since certain parts of the configuration need to be re-established each time a new development environment is opened. Chapter three provides a debugging tool, next-drupal-debug, that uses the expected connection credentials (on the Next.js side) to test that Drupal has been properly configured. This demo template includes a copy of this tool, which has been modified slightly to pull those credentials from environment variables. You will see that the connection is tested during the post_deploy hook in .platform.app.yaml to ensure everything is working properly.

Migrating

Read the #customizations section first if you have not already. It contains added files that are required to deploy on Platform.sh, and that will be necessary to migrate Drupal, and to deploy a Next.js site alongside it. For your own migration, Platform.sh recommends that you deploy and migrate Drupal first according to the recommendations in our Drupal 9 migration guide, then consult the following steps so that you can consistently deploy it with Next.js.

This repository is intended to be a demo. It makes certain decisions so that users can quickly deploy a full Next.js + Drupal project that

  1. Will work automatically across development environments.
  2. Deploys successfully upon initialization, with a single click.
  3. Comes with generated dummy content to showcase the final application.

In reality, only the first point is relevant for your migration, but this section attempts to explain the full logic of how configuration is handled to be the most helpful to your use case. It follows the steps outlined exactly in the Next.js-Drupal documentation, only deviating when Platform.sh-specifics need to be addressed.

Summary and Platform.sh development environment configuration logic

In the Next.js-Drupal documentation a completely fresh Drupal installation is our starting point, as it is in this template. A number of configuration changes are made to Drupal (adding modules, configuring a consumer, generating keys, etc.) that make it a valid API that a specific Next.js site can consume. Then a Next.js frontend provided by Chapter Three is cloned and used for the frontend.

Part of the documentation's assumptions are the fact that the final Drupal site will be deployed somewhere, and that the Next.js site will be deployed somewhere else. Going forward, everything about the frontend and backend connection credentials are hard-coded and must be updated by the developer into their pipeline.

Platform.sh works differently. We assume that Drupal and Next.js will be deployed together to a single final environment. There are some advantages to this approach, namely that the location and connection secrets for the backend can be pulled from the environment itself rather than hardcoded. Also, because of this, it's possible to branch off new development environments that likewise have access to these credentials.

In order to accomplish, some of the configuration described in the Next.js-Drupal documentation has to be accomplished once when the demo is first deployed, while others have to be run on the first deployment of each new environment. As you might expect, the steps run only once can be executed manually during migration on the production environment. They are included here in the case that you have many of these kinds of sites being deployed in a fleet, where some automation is desired. For the most part however, the environment-level configuration of the second kind will need to be replicated or copied in your own migration, for which this template provides one example of how to do it.

How configuration is tracked across enviroments

There are a lot of moving parts to make this relationship work. Because of this, there is a committed api/platformsh-scripts/settings.default.json included with this template. On a quick glance, most of the settings described in the Next.js-Drupal documentation are included here. Other values (like secret keys) are pulled from non-public Platform.sh-provided environment variables during deployment.

It's with this file that we will set both project and environment level configuration. It is placed in a network storage mount, so that we can retain write access to it when new environments are created. You can view this contents of this file by SSHing into either application container and viewing deploy/settings.json.

Besides that, all of the steps below that either configure Drupal or modify this file can be found from api/platformsh-scripts/hooks.deploy.sh. By following the comments in that script, along with the accompanying called scripts for each step, you should have everything you need to track and replicate for your own migration. File names and locations relevant to this demo can be found in api/.environment.

Project-level configuration: initializing the production environment

Below are the steps taken during Drupal's deploy hook only on the first deployment:

  1. api/platformsh-scripts/settings.default.json is copied to a well-defined writable location.
  2. Drupal is installed using the standard profile and an intial admin password pulled from the environment.
  3. Modules relevant to Next.js-Drupal are enabled.
  4. A role and user are created.
  5. Content is configured. This step is will likely not be neeed in your migration. Because of this, the script 04-configure-content checks for two environment variables (CREATE_DEMO_NODES and CREATE_PATHAUTO_ALIASES) that are set in api/.platform.app.yaml. If you do not need to 1) configure pathauto aliases, or 2) generate dummy articles, you can set both of those values to false. Once you have dont that, it should be possible to copy the platformsh-scripts directory completely and run it for your own migration.

When you first deploy this template, the activity log should look like this for the deploy hook:

Executing deploy hook for application drupal
Created Drush configuration file: /app/.drush/drush.yml

* Fresh project detected.
   ✔ Installing Drupal with a Standard profile (see https://next-drupal.org/learn/quick-start/install-drupal).
   ✔ Installation complete.

   ✔ Your Drupal site has been installed with the following credentials:
      * user: admin
      * pass: PASSWORD-GENERATED-HERE-ON-FIRST-PUSH
   ✗ WARNING: Update your password and email immediately. They will only be available once.
   ✔ Enabing modules (see https://next-drupal.org/learn/quick-start/enable-modules).
      * next
      * next_jsonapi
   ✔ Creating role (see https://next-drupal.org/learn/quick-start/create-role).
      * id: oauth_consumer_role
      * label: OAuth Consumer Role
   ✔ Defining role permissions (see https://next-drupal.org/learn/quick-start/create-role).
      * bypass node access
      * issue subrequests
      * access user profiles
   ✔ Creating user (see https://next-drupal.org/learn/quick-start/create-role).
      * id: oauth_consumer_user
   ✔ Granting role permissions to user (see https://next-drupal.org/learn/quick-start/create-role)
      * user_id: oauth_consumer_user
      * role_id: oauth_consumer_role
   ✔ Tracking user (see https://next-drupal.org/learn/quick-start/create-role).
      * id: oauth_consumer_user
      * uid: 2
   ✔ Defining node aliases via pathauto (see https://next-drupal.org/learn/quick-start/configure-content-types).
      * type: node
      * bundle: article
      * label: Article
      * pattern: /blog/[node:title]
   ✔ Generating demo article nodes (see https://next-drupal.org/learn/quick-start/create-content).
      * data: 04-dummy-nodes.json
      * num_nodes: 15
      ! Get some coffee, this will take a moment...
      * node 0: A Circumhorizontal Arc Over Ohio
      * node 1: Pwyll: Icy Crater of Europa
      ...
      ...
      * node 14: Dark Craters and Bright Spots Revealed on Asteroid Ceres
   ✔ Updating default theme.
   ✔ Rebuilding the cache.

There will be additional steps after that, but those are addressed in the next section on Environment-level configuration.

Environment-level configuration: Reconfiguring every new environment

At this point in the Next.js-Drupal documentation you would configure a consumer associated with a specific Next.js frontend url location. On Platform.sh, this location will entirely depend on which development environment we're on, so this configuration has to be done on every new environment, instead of just once at the project-level.

  1. In the first step, its determined whether or not we're running on a newly created environment. Every development environment on Platform.sh inherits data from its parent, so this first step resets all of the configuration described in the next steps if it is indeed a new environment.

  2. A new consumer is created for the environment, and OAuth is configured for it.

  3. A Next.js site entity is created, and previews are configured.

  4. In the last step executed in 04-track-environment.sh, it may seem like a lot of things are going on. The summary is as follows:

    a. Our tracking settings file is updated to reflect the changes for the current environment. b. A platformsh.environment file is generated. You will recognize this file as containing all of the required environment variables for the Next.js side. In this step, the file is created, and then saved into a network storage mount. Network storage is a helpful service, because once moved there the frontend Next.js container will have access to it. c. Almost identically to the above, a platformsh.env file is generated. While the above is meant to be used within a Platform.sh environment, this file is meant to be used for local development. You can see the [#local-development](Local Development) section for details, but the important point is that the script /client/get_local_config.sh can be run to retrieve this file for the current environment while you are working.

When a new environment is created, the deploy hook will look like the below in the activity log:

* New environment detected.
   ✔ Deleting parent environment's configuration
* Configuring the current environment.
   ✔ Generating keys (see https://next-drupal.org/learn/quick-start/create-consumer).
      * location: /app/private
      * public_key: /app/private/public.key
      * private_key: /app/private/private.key
   ✔ Creating the OAuth consumer for the current environment (see https://next-drupal.org/learn/quick-start/create-consumer).
      * user_uid: 2
      * consumer_id: oauth_consumer_env
      * consumer_label: Next.js OAuth Env Consumer
      * consumer_site: oauth_consumer_role
      * consumer_secret: SOME_SECRET
      * consumer_uid: SOME_ID
   ✔ Creating the NextJS site entity (see https://next-drupal.org/learn/quick-start/create-nextjs-site).
      * id: nextjs_site
      * label: Next.js Site
      * base_url: https://ENVIRONMENT-HASH-PROJECT_ID.eu-3.platformsh.site
      * preview_url: https://ENVIRONMENT-HASH-PROJECT_ID.eu-3.platformsh.site/api/preview
      * preview_secret: ENVIRONMENT-HASH
   ✔ Configuring previews (see https://next-drupal.org/learn/quick-start/configure-content-types).
      * site: nextjs_site
      * id: node.article
      * site_resolver: site_selector
   ✔ Logging frontend configuration.
* Preparing credentials to hand off to frontend container.
* Writing local configuration.

After this line, two configuration files are shown - a .env.local and a .environment file - which are used to help you develop locally and connect to the backend within a Platform.sh environment, respectively.

Contact

This template is maintained primarily by the Platform.sh Developer Relations team, and they will be notified of all issues and pull requests you open here.

  • Community: Share your question with the community, or see if it's already been asked on our Community site.
  • Slack: If you haven't done so already, you can join Platform.sh's public Slack channels and ping the @devrel_team with any questions.

Resources

Contributing

Help us keep top-notch templates!

Every one of our templates is open source, and they're important resources for users trying to deploy to Platform.sh for the first time or better understand the platform. They act as getting started guides, but also contain a number of helpful tips and best practices when working with certain languages and frameworks.

See something that's wrong with this template that needs to be fixed? Something in the documentation unclear or missing? Let us know!

How to contribute


Report a bug
Submit a feature request
Open a pull request


Need help?


Ask the Platform.sh Community
Join us on Slack



Thanks to all of our amazing contributors!


GitHub Contributors Image