Gradle AEM Plugin (GAP)

Gradle AEM Plugin (GAP) is a Gradle plugin that provides many tasks related to AEM development, such as launching, provisioning, restarting, backing up, restoring, and destroying instances, deploying packages, synchronizing content between a local repository and a running instance, copying content between instances, tailing logs, and more. All of these tasks are incremental builds that take seconds, not minutes.

GAP Launcher

To run GAP, you need a project that has at least Gradle Wrapper files and minimal Gradle configuration that applies the Gradle AEM Plugin. However, some GAP features can be useful even when you're not building an AEM application, and that's where the GAP Launcher comes in handy. It's a standalone launcher that provides GAP features with minimal effort. To get it working, download the latest jar from GitHub releases page, or simply run the following command in the directory where you want to use it:

curl -OJL && java -jar gap.jar && rm gap.jar

This will download the latest GAP jar file and run it, then delete the jar file.

You can now use the Gradle wrapper to run the tasks provided by GAP.

Instances Setup and Requirements

You need access to the following:

  1. A local or remote AEM on-prem author instance
  2. An AEM author instance running on Adobe cloud infrastructure (AEMaaCS)

For a regular on-prem AEM instance, basic authentication (username and password) is sufficient. However, with AEMaaCS, Adobe doesn't share these credentials, so authentication must be performed using a bearer token. GAP can generate this token if you provide it with a JSON file that you can download from the cloud developer console, as shown in the image below.

Adobe cloud Developer Console, for a selected environment and pod, in the Integrations tab, the "Get Service Credentials" can be used to download the JSON file.

Adobe cloud developer console image by Adobe

Writing a Migration Task with GAP

Add the following snippet to build.gradle.kts file to extend GAP tasks with this custom "migrate" task which when you run will copy all the content you have under a specified path from your on-prem AEM author to the same path in your AEMaaCS author.

tasks.register("migrate") {
  doLast {
    val author1 = aem.instance("http://<username>:<password>@localhost:4502")

    val author2 = aem.instance("https://<author-name>")

    val pkg = {

  • aem - AemExtension is the core of GAP and represents the facade for implementing tasks.
  • aem.instance is a shorthand method for getting/creating a defined Instance by URL
  • author1 represents your on-prem author instance. Notice that you can set the username and password through the URL.
  • author2 represents your AEMaaCS author instance in this case because of passing the domain.
  • serviceCredentials is a property in the instance object where you can specify the path to the earlier downloaded JSON credentials file.
  • sync - InstanceSync is a class that provides access to AEM-specific resources (OSGI, JCR, CRX, GroovyConsole, etc.) to perform synchronization tasks.
  • packageManager - PackageManager is a class to manage CRX packages on an AEM instance (upload, install, delete, etc.).
  • will download the package with the location specified in the filter object from author1.
  • sync.packageManager.deploy will deploy that downloaded package and install it to author2.

you can now execute the following command to run the task whenever you want to migrate content between those two instances:

sh gradlew migrate


As you have seen, implementing automation in GAP is very easy and powerful, we were able to migrate content to AEMaaCS in a couple of lines of code. You could definitely use it in a daily development routine together with AEMaaCS SDK.

For more information on GAP, check out the GAP GitHub repository. Additionally, the plugin documentation contains a lot of examples and use cases that will help you to understand how to use GAP in your specific situation.