diff --git a/contrib/teamcity/build-configurations.py b/contrib/teamcity/build-configurations.py
--- a/contrib/teamcity/build-configurations.py
+++ b/contrib/teamcity/build-configurations.py
@@ -130,6 +130,9 @@
         }
 
     def create_script_file(self, dest, content):
+        # Ensure the directory exists
+        dest.parent.mkdir(parents=True, exist_ok=True)
+
         # Write the content to a script file using a template
         with open(
             self.script_root.joinpath("bash_script.sh.in"), encoding="utf-8"
@@ -157,15 +160,34 @@
         #    should be run parallel.
         script = self.config.get("script", None)
         if script:
+            # Initialize build_steps as an empty array
+            self.build_steps = []
+            # Handle dependencies first if they exist
+            depends = self.config.get("depends", [])
+            for dep in depends:
+                dep_config = BuildConfiguration(self.script_root, self.config_file, dep)
+                # create build file for this script
+                dep_script_file = dep_config.build_directory.joinpath("script.sh")
+                dep_script = dep_config.get("script", None)
+                dep_config.create_script_file(dep_script_file, dep_script)
+                # Add script to build this dep to steps
+                self.build_steps.append(
+                    {
+                        "bin": str(dep_script_file),
+                        "args": [],
+                    }
+                )
+
             script_file = self.build_directory.joinpath("script.sh")
             self.create_script_file(script_file, script)
 
-            self.build_steps = [
+            # Add a step for the actual specified script
+            self.build_steps.append(
                 {
                     "bin": str(script_file),
                     "args": [],
                 }
-            ]
+            )
             return
 
         # Check for a docker configuration
@@ -403,6 +425,23 @@
         # If a post build script is defined, add it as a last step
         post_build = self.config.get("post_build", None)
         if post_build:
+            # Note that we must build dependencies post_build
+            # In practice, this is how the js-mocha-integration-tests template works
+            depends = self.config.get("depends", [])
+            for dep in depends:
+                dep_config = BuildConfiguration(self.script_root, self.config_file, dep)
+                # create build file for this script
+                dep_script_file = dep_config.build_directory.joinpath("script.sh")
+                dep_script = dep_config.get("script", None)
+                dep_config.create_script_file(dep_script_file, dep_script)
+                # Add script to build this dep to steps
+                self.build_steps.append(
+                    {
+                        "bin": str(dep_script_file),
+                        "args": [],
+                    }
+                )
+
             script_file = self.build_directory.joinpath("post_build.sh")
             self.create_script_file(script_file, post_build)
 
diff --git a/contrib/teamcity/build-configurations.yml b/contrib/teamcity/build-configurations.yml
--- a/contrib/teamcity/build-configurations.yml
+++ b/contrib/teamcity/build-configurations.yml
@@ -79,89 +79,6 @@
       PROJECT_NAME="$(basename ${JS_PROJECT_ROOT})"
       TEST_SUITE_NAME="$(project_to_suite ${PROJECT_NAME})"
 
-      # Install b58-ts dependencies if this test uses them
-      if [ -z "${DEPENDS_B58_TS+x}" ] ; then
-        echo "Test does not depend on b58-ts, skipping b58-ts dependencies..."
-      else
-        echo "Test depends on b58-ts. Installing b58-ts dependencies..."
-        pushd "${TOPLEVEL}/modules/b58-ts"
-        npm ci
-        npm run build
-      fi
-
-      # Install ecashaddrjs dependencies if this test uses them
-      if [ -z "${DEPENDS_ECASHADDRJS+x}" ] ; then
-        echo "Test does not depend on ecashaddrjs, skipping ecashaddrjs dependencies..."
-      else
-        echo "Test depends on ecashaddrjs. Installing ecashaddrjs dependencies..."
-        pushd "${TOPLEVEL}/modules/ecashaddrjs"
-        npm ci
-        npm run build
-      fi
-
-      # Build ecash-lib-wasm for ecash-lib's WebAssembly part
-      if [ -z "${DEPENDS_ECASH_LIB_WASM+x}" ] ; then
-        echo "Test does not depend on ecash-lib-wasm, skipping"
-      else
-        echo "Test depends on ecash-lib-wasm. Building WebAssembly..."
-        pushd "${TOPLEVEL}/modules/ecash-lib-wasm"
-        ./build-wasm.sh
-      fi
-
-      if [ -z "${DEPENDS_CHRONIK_CLIENT+x}" ] ; then
-        echo "Test does not depend on chronik-client"
-      else
-        echo "Test depends on chronik-client. Building TypeScript..."
-        pushd "${TOPLEVEL}/modules/chronik-client"
-        npm ci
-      fi
-
-      # Install mock-chronik-client dependencies if this test uses them
-      if [ -z "${DEPENDS_MOCK_CHRONIK_CLIENT+x}" ] ; then
-        echo "Test does not depend on mock-chronik-client, skipping mock-chronik-client dependencies..."
-      else
-        echo "Test depends on mock-chronik-client. Installing mock-chronik-client dependencies..."
-        pushd "${TOPLEVEL}/modules/mock-chronik-client"
-        npm ci
-        npm run build
-      fi
-
-      if [ -z "${DEPENDS_ECASH_LIB+x}" ] ; then
-        echo "Test does not depend on ecash-lib"
-      else
-        echo "Test depends on ecash-lib. Building TypeScript..."
-        pushd "${TOPLEVEL}/modules/ecash-lib"
-        npm ci
-        npm run build
-      fi
-
-      if [ -z "${DEPENDS_ECASH_AGORA+x}" ] ; then
-        echo "Test does not depend on ecash-agora"
-      else
-        echo "Test depends on ecash-agora. Building TypeScript..."
-        pushd "${TOPLEVEL}/modules/ecash-agora"
-        npm ci
-        npm run build
-      fi
-
-      # Install ecash-script dependencies if this test uses them
-      if [ -z "${DEPENDS_ECASH_SCRIPT+x}" ] ; then
-        echo "Test does not depend on ecash-script, skipping ecash-script dependencies..."
-      else
-        echo "Test depends on ecash-script. Installing ecash-script dependencies..."
-        pushd "${TOPLEVEL}/modules/ecash-script"
-        npm ci
-      fi
-
-      # Install ecash-coinselect dependencies if this test uses them
-      if [ -z "${DEPENDS_ECASH_COINSELECT+x}" ] ; then
-        echo "Test does not depend on ecash-coinselect, skipping ecash-coinselect dependencies..."
-      else
-        echo "Test depends on ecash-coinselect. Installing ecash-coinselect dependencies..."
-        pushd "${TOPLEVEL}/modules/ecash-coinselect"
-        npm ci
-      fi
-
       pushd "${TOPLEVEL}/${JS_PROJECT_ROOT}"
 
       MOCHA_JUNIT_DIR="test_results"
@@ -223,59 +140,16 @@
       PROJECT_NAME="$(basename ${JS_PROJECT_ROOT})"
       TEST_SUITE_NAME="$(project_to_suite ${PROJECT_NAME})"
 
-       # Install b58-ts dependencies if this test uses them
-      if [ -z "${DEPENDS_B58_TS+x}" ] ; then
-        echo "Test does not depend on b58-ts, skipping b58-ts dependencies..."
-      else
-        echo "Test depends on b58-ts. Installing b58-ts dependencies..."
-        pushd "${TOPLEVEL}/modules/b58-ts"
-        npm ci
-        npm run build
-      fi
-
-      # Install ecashaddrjs dependencies if this test uses them
-      if [ -z "${DEPENDS_ECASHADDRJS+x}" ] ; then
-        echo "Test does not depend on ecashaddrjs, skipping ecashaddrjs dependencies..."
-      else
-        echo "Test depends on ecashaddrjs. Installing ecashaddrjs dependencies..."
-        pushd "${TOPLEVEL}/modules/ecashaddrjs"
-        npm ci
-        npm run build
-      fi
-
-      # Build ecash-lib-wasm for ecash-lib's WebAssembly part
-      if [ -z "${DEPENDS_ECASH_LIB_WASM+x}" ] ; then
-        echo "Test does not depend on ecash-lib-wasm, skipping"
-      else
-        echo "Test depends on ecash-lib-wasm. Building WebAssembly..."
-        pushd "${TOPLEVEL}/modules/ecash-lib-wasm"
-        ./build-wasm.sh
-      fi
-
-      if [ -z "${DEPENDS_CHRONIK_CLIENT+x}" ] ; then
-        echo "Test does not depend on chronik-client"
-      else
-        echo "Test depends on chronik-client. Building TypeScript..."
-        pushd "${TOPLEVEL}/modules/chronik-client"
-        npm ci
-      fi
-
-      if [ -z "${DEPENDS_ECASH_LIB+x}" ] ; then
-        echo "Test does not depend on ecash-lib"
-      else
-        echo "Test depends on ecash-lib. Building TypeScript..."
-        pushd "${TOPLEVEL}/modules/ecash-lib"
-        npm ci
-        npm run build
-      fi
-
       pushd "${TOPLEVEL}/${JS_PROJECT_ROOT}"
 
       MOCHA_JUNIT_DIR="test_results"
       MOCHA_JUNIT_PATH="${MOCHA_JUNIT_DIR}/${PROJECT_NAME}-integration-tests-junit.xml"
       rm -rf "${MOCHA_JUNIT_DIR}" && mkdir -p "${MOCHA_JUNIT_DIR}"
 
+      # Install deps and build
+      # Note that all js-mocha-integration-tests template builds are ts and must be built
       npm ci
+      npm run build
 
       # Make sure the report is available even if the tests fail
       move_junit_report() {
@@ -785,6 +659,75 @@
     script: |
       "${TOPLEVEL}/test/lint/lint-circular-dependencies.sh"
 
+  # Build monorepo-hosted npm module b58-ts
+  b58-ts:
+    script: |
+      echo "Test depends on b58-ts. Installing b58-ts dependencies..."
+      pushd "${TOPLEVEL}/modules/b58-ts"
+      npm ci
+      npm run build
+
+  # Build monorepo-hosted npm module ecashaddrjs
+  ecashaddrjs:
+    script: |
+      echo "Test depends on ecashaddrjs. Installing ecashaddrjs dependencies..."
+      pushd "${TOPLEVEL}/modules/ecashaddrjs"
+      npm ci
+      npm run build
+
+  # Build monorepo-hosted npm module ecash-lib-wasm
+  ecash-lib-wasm:
+    script: |
+      echo "Test depends on ecash-lib-wasm. Building WebAssembly..."
+      pushd "${TOPLEVEL}/modules/ecash-lib-wasm"
+      ./build-wasm.sh
+
+  # Build monorepo-hosted npm module chronik-client
+  chronik-client:
+    script: |
+      echo "Test depends on chronik-client. Building TypeScript..."
+      pushd "${TOPLEVEL}/modules/chronik-client"
+      npm ci
+      npm run build
+
+  # Build monorepo-hosted npm module mock-chronik-client
+  mock-chronik-client:
+    script: |
+      echo "Test depends on mock-chronik-client. Installing mock-chronik-client dependencies..."
+      pushd "${TOPLEVEL}/modules/mock-chronik-client"
+      npm ci
+      npm run build
+
+  # Build monorepo-hosted npm module ecash-lib
+  ecash-lib:
+    script: |
+      echo "Test depends on ecash-lib. Building TypeScript..."
+      pushd "${TOPLEVEL}/modules/ecash-lib"
+      npm ci
+      npm run build
+
+  # Build monorepo-hosted npm module ecash-agora
+  ecash-agora:
+    script: |
+      echo "Test depends on ecash-agora. Building TypeScript..."
+      pushd "${TOPLEVEL}/modules/ecash-agora"
+      npm ci
+      npm run build
+
+  # Build monorepo-hosted npm module ecash-script
+  ecash-script:
+    script: |
+      echo "Test depends on ecash-script. Installing ecash-script dependencies..."
+      pushd "${TOPLEVEL}/modules/ecash-script"
+      npm ci
+
+  # Build monorepo-hosted npm module ecash-coinselect
+  ecash-coinselect:
+    script: |
+      echo "Test depends on ecash-coinselect. Installing ecash-coinselect dependencies..."
+      pushd "${TOPLEVEL}/modules/ecash-coinselect"
+      npm ci
+
   cashtab-tests:
     runOnDiffRegex:
       - cashtab/
@@ -884,10 +827,11 @@
       - modules/ecashaddrjs/
     env:
       JS_PROJECT_ROOT: apps/alias-server
-      DEPENDS_ECASHADDRJS: "true"
-      DEPENDS_ECASH_SCRIPT: "true"
-      DEPENDS_CHRONIK_CLIENT: "true"
-      DEPENDS_MOCK_CHRONIK_CLIENT: "true"
+    depends:
+      - ecashaddrjs
+      - ecash-script
+      - chronik-client
+      - mock-chronik-client
     templates:
       - js-mocha
 
@@ -899,14 +843,15 @@
       - modules/chronik-client/
     env:
       JS_PROJECT_ROOT: apps/ecash-herald
-      DEPENDS_MOCK_CHRONIK_CLIENT: "true"
-      DEPENDS_CHRONIK_CLIENT: "true"
-      DEPENDS_ECASH_SCRIPT: "true"
-      DEPENDS_ECASHADDRJS: "true"
-      DEPENDS_ECASH_LIB_WASM: "true"
-      DEPENDS_B58_TS: "true"
-      DEPENDS_ECASH_LIB: "true"
-      DEPENDS_ECASH_AGORA: "true"
+    depends:
+      - b58-ts
+      - ecashaddrjs
+      - chronik-client
+      - ecash-lib-wasm
+      - ecash-lib
+      - ecash-agora
+      - ecash-script
+      - mock-chronik-client
     templates:
       - js-mocha
 
@@ -918,13 +863,14 @@
       - modules/chronik-client/
     env:
       JS_PROJECT_ROOT: apps/token-server
-      DEPENDS_MOCK_CHRONIK_CLIENT: "true"
-      DEPENDS_ECASHADDRJS: "true"
-      DEPENDS_CHRONIK_CLIENT: "true"
-      DEPENDS_ECASH_LIB_WASM: "true"
-      DEPENDS_B58_TS: "true"
-      DEPENDS_ECASH_LIB: "true"
       RUN_NPM_BUILD: "true"
+    depends:
+      - b58-ts
+      - ecashaddrjs
+      - chronik-client
+      - mock-chronik-client
+      - ecash-lib-wasm
+      - ecash-lib
     templates:
       - js-mocha
 
@@ -934,7 +880,8 @@
       - modules/ecashaddrjs/
     env:
       JS_PROJECT_ROOT: modules/mock-chronik-client
-      DEPENDS_ECASHADDRJS: "true"
+    depends:
+      - ecashaddrjs
     templates:
       - js-mocha
 
@@ -953,7 +900,8 @@
       - modules/ecashaddrjs/
     env:
       JS_PROJECT_ROOT: modules/chronik-client
-      DEPENDS_ECASHADDRJS: "true"
+    depends:
+      - ecashaddrjs
     templates:
       - js-mocha
 
@@ -966,10 +914,11 @@
     env:
       JS_PROJECT_ROOT: modules/ecash-lib
       RUN_NPM_BUILD: "true"
-      DEPENDS_B58_TS: "true"
-      DEPENDS_ECASH_LIB_WASM: "true"
-      DEPENDS_ECASHADDRJS: "true"
-      DEPENDS_CHRONIK_CLIENT: "true"
+    depends:
+      - b58-ts
+      - ecash-lib-wasm
+      - ecashaddrjs
+      - chronik-client
     templates:
       - js-mocha
 
@@ -981,11 +930,11 @@
       - src/secp256k1/
     env:
       JS_PROJECT_ROOT: modules/ecash-agora
-      DEPENDS_ECASHADDRJS: "true"
-      DEPENDS_ECASH_LIB_WASM: "true"
-      DEPENDS_CHRONIK_CLIENT: "true"
-      DEPENDS_B58_TS: "true"
-      DEPENDS_ECASH_LIB: "true"
+    depends:
+      - b58-ts
+      - ecashaddrjs
+      - ecash-lib-wasm
+      - ecash-lib
     templates:
       - js-mocha
 
@@ -1007,11 +956,12 @@
       - Cargo.lock
     env:
       JS_PROJECT_ROOT: modules/ecash-agora
-      DEPENDS_ECASHADDRJS: "true"
-      DEPENDS_ECASH_LIB_WASM: "true"
-      DEPENDS_CHRONIK_CLIENT: "true"
-      DEPENDS_B58_TS: "true"
-      DEPENDS_ECASH_LIB: "true"
+    depends:
+      - b58-ts
+      - ecashaddrjs
+      - chronik-client
+      - ecash-lib-wasm
+      - ecash-lib
     templates:
       - js-mocha-integration-tests
 
@@ -1031,10 +981,11 @@
       - Cargo.lock
     env:
       JS_PROJECT_ROOT: modules/ecash-lib
-      DEPENDS_B58_TS: "true"
-      DEPENDS_ECASH_LIB_WASM: "true"
-      DEPENDS_ECASHADDRJS: "true"
-      DEPENDS_CHRONIK_CLIENT: "true"
+    depends:
+      - b58-ts
+      - ecashaddrjs
+      - ecash-lib-wasm
+      - chronik-client
     templates:
       - js-mocha-integration-tests
 
@@ -1052,7 +1003,8 @@
       - Cargo.lock
     env:
       JS_PROJECT_ROOT: modules/chronik-client
-      DEPENDS_ECASHADDRJS: "true"
+    depends:
+      - ecashaddrjs
     templates:
       - js-mocha-integration-tests