diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 24c9533e2f3becec77cdc7c9b42f28a0fe294338..a866b7c66c9baa05bbf19f69ae0068caf460b500 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,10 +1,10 @@
 variables:
   DATA_CONUS_2018A: conus-2018a
   DATA_URL: ${S3_BUCKET}/nshmp_2018a_v1.1-CONUS-hazards-with-preliminary-PGV-fv0.3-1x1.nc
+  IMAGE_NAME: ${CODE_REGISTRY_IMAGE}/${CI_PROJECT_NAME}:${ENVIRONMENT}-${CI_COMMIT_SHORT_SHA}
   # TODO: Remove hard coded url
   S3_BUCKET: https://nshmp-netcdf-lp-development-rbucket-1of3d1x45yfd9.s3-us-west-2.amazonaws.com
 
-
 # Do not run for merge requests
 workflow:
   rules:
@@ -20,6 +20,7 @@ stages:
   - init
   - build
   - deploy
+  - trigger
 
 ####
 # Template: Common Gradle test
@@ -31,7 +32,6 @@ stages:
   tags:
     - development
 
-
 .templates:
   adjust-ref: &adjust-ref |
     if [[ \
@@ -105,6 +105,7 @@ Build Image 2018:
       FROM_IMAGE=${DEVOPS_REGISTRY}usgs/java:11
       ci_job_token=${CI_JOB_TOKEN}
       netcdf_file=DATA/data.nc
+    UPSTREAM_PATH: ghsc/nshmp/nshmp-netcdf
 
 Build Project:
   extends:
@@ -133,6 +134,8 @@ Unit Tests:
   coverage: '/Total.*?([0-9]{1,3})%/'
   extends:
     - .gradle
+  needs:
+    - Init
   rules:
     -
       changes:
@@ -152,6 +155,8 @@ Unit Tests:
 Markdown Lint:
   extends:
     - .gradle
+  needs:
+    - Init
   rules:
     -
       changes:
@@ -168,6 +173,8 @@ Markdown Lint:
 YAML Lint:
   extends:
     - .gradle
+  needs:
+    - Init
   rules:
     -
       changes:
@@ -189,9 +196,49 @@ Staging 01:
     - .deploy
     - .onprem-staging
     - .staging01
+  needs:
+    - Build Image 2018
+    - Build Project
+    - Init
+    - Markdown Lint
+    - Unit Tests
+    - YAML Lint
 
 # Staging 02:
 #   extends:
 #     - .deploy
 #     - .onprem-staging
 #     - .staging02
+
+####
+# Stage: trigger
+####
+
+Trigger nshmp-webapps:
+  needs:
+    - Build Image 2018
+  rules:
+    -
+      if: !reference [.development-env, if]
+      variables: !reference [.development-env, variables]
+      when: manual
+    - !reference [.staging-env]
+    - !reference [.production-env]
+  parallel:
+    matrix:
+      - REGION: us-west-2
+  script:
+    - apk add curl
+    - |
+      curl --request POST \
+        --form token=${NSHMP_WEBAPPS_CDK_TRIGGER_TOKEN} \
+        --form ref=main \
+        --form description="Triggered by nshmp-netcdf" \
+        --form "variables[CDK_DEPLOY_REGION]=${REGION}" \
+        --form "variables[ENVIRONMENT]=${ENVIRONMENT}" \
+        --form "variables[IMAGE]=${IMAGE_NAME}" \
+        --form "variables[STACK_NAME]=nshmp-netcdf-conus-2018a" \
+        "https://code.chs.usgs.gov/api/v4/projects/${NSHMP_WEBAPPS_CDK_PROJECT_ID}/trigger/pipeline"
+  stage: trigger
+  variables:
+    UPSTREAM_PATH: ghsc/nshmp/nshmp-netcdf
diff --git a/build.gradle b/build.gradle
index ae4d8ffafbfb93740481363c37c544412d346777..86f3682a217b6a5eb0e94ca7c2b3252b7ee86b3b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -31,6 +31,7 @@ ext {
 
 apply from: "${projectDir}/gradle/repositories.gradle"
 apply from: "${projectDir}/gradle/dependencies.gradle"
+apply from: "${projectDir}/gradle/node.gradle"
 
 test {
   useJUnitPlatform()
@@ -99,7 +100,6 @@ gradle.afterProject {
     into nshmpLib
   }
   apply from: "${nshmpLibGradleDir}/git-hooks.gradle"
-  apply from: "${nshmpLibGradleDir}/node.gradle"
   apply from: "${nshmpLibGradleDir}/spotbugs.gradle"
   apply from: "${nshmpLibGradleDir}/spotless.gradle"
 }
diff --git a/gradle/node.gradle b/gradle/node.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..44beda13e6097d2f6027bda70a3bb865ca2b633c
--- /dev/null
+++ b/gradle/node.gradle
@@ -0,0 +1,51 @@
+apply plugin: "com.github.node-gradle.node"
+
+node {
+  download = true
+  version = "14.16.0"
+}
+
+/* Install markdownlint-cli with NPM */
+task nodeInstall(type: NpmTask) {
+  description "Install markdownlint-clia and yamllint with NPM"
+  args = [
+    "install",
+    "markdownlint-cli",
+    "yaml-lint",
+    "--save-dev",
+    "--loglevel",
+    "error"
+  ]
+}
+
+/* Run markdownlint */
+task markdownlint(type: NpxTask) {
+  description "Run markdownlint"
+  dependsOn nodeInstall
+  command = "markdownlint"
+  args = ["**/*.md"]
+}
+
+/* Apply markdownlint fixes */
+task markdownlintApply(type: NpxTask) {
+  description "Apply markdownlint fixes"
+  dependsOn nodeInstall
+  command = "markdownlint"
+  args = [
+    "**/*.md",
+    "--fix",
+  ]
+}
+
+/* Run yamllint */
+task yamllint(type: NpxTask) {
+  description "Run yamllint"
+  dependsOn nodeInstall
+  command = "yamllint"
+  args = [
+    "**/*.yml",
+    "--ignore=.gradle/**",
+    "--ignore=node_modules/**",
+    "--ignore=.gitlab-ci.yml"
+  ]
+}