diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 65c2f9495e7d0..2e7dc13a8eabd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,8 +14,6 @@ jobs:
     steps:
       - name: Checkout sources
         uses: actions/checkout@v2
-        with:
-          submodules: true
 
       - name: Install stable toolchain
         uses: actions-rs/toolchain@v1
@@ -53,8 +51,6 @@ jobs:
     steps:
       - name: Checkout sources
         uses: actions/checkout@v2
-        with:
-          submodules: true
 
       - name: Install stable toolchain
         uses: actions-rs/toolchain@v1
@@ -81,6 +77,28 @@ jobs:
           path: target
           key: ${{ runner.os }}-v2-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}
 
+      - name: Cache test tree-sitter-grammar
+        uses: actions/cache@v2.1.7
+        with:
+          path: runtime/grammars
+          key: ${{ runner.os }}-v2-tree-sitter-grammars-${{ hashFiles('**/Cargo.lock') }}
+
+      - run: cp .github/workflows/languages.toml ./languages.toml
+
+      - name: Download test tree-sitter grammar
+        uses: actions-rs/cargo@v1
+        with:
+          use-cross: ${{ matrix.cross }}
+          command: run
+          args: -- --fetch-grammars
+
+      - name: Build test tree-sitter grammar
+        uses: actions-rs/cargo@v1
+        with:
+          use-cross: ${{ matrix.cross }}
+          command: run
+          args: -- --build-grammars
+
       - name: Run cargo test
         uses: actions-rs/cargo@v1
         with:
@@ -97,8 +115,6 @@ jobs:
     steps:
       - name: Checkout sources
         uses: actions/checkout@v2
-        with:
-          submodules: true
 
       - name: Install stable toolchain
         uses: actions-rs/toolchain@v1
@@ -144,8 +160,6 @@ jobs:
     steps:
       - name: Checkout sources
         uses: actions/checkout@v2
-        with:
-          submodules: true
 
       - name: Install stable toolchain
         uses: actions-rs/toolchain@v1
diff --git a/.github/workflows/languages.toml b/.github/workflows/languages.toml
new file mode 100644
index 0000000000000..18cf71cf5ff7c
--- /dev/null
+++ b/.github/workflows/languages.toml
@@ -0,0 +1,26 @@
+# This languages.toml is used for testing in CI.
+
+[[language]]
+name = "rust"
+scope = "source.rust"
+injection-regex = "rust"
+file-types = ["rs"]
+comment-token = "//"
+roots = ["Cargo.toml", "Cargo.lock"]
+indent = { tab-width = 4, unit = "    " }
+
+[[grammar]]
+name = "rust"
+source = { git = "https://github.com/tree-sitter/tree-sitter-rust", rev = "a360da0a29a19c281d08295a35ecd0544d2da211" }
+
+[[language]]
+name = "nix"
+scope = "source.nix"
+injection-regex = "nix"
+file-types = ["nix"]
+shebangs = []
+roots = []
+comment-token = "#"
+
+# A grammar entry is not necessary for this language - it is only used for
+# testing TOML merging behavior.
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 7b0b7ee244980..31b2f26fad863 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -53,8 +53,6 @@ jobs:
     steps:
       - name: Checkout sources
         uses: actions/checkout@v2
-        with:
-          submodules: true
 
       - name: Install ${{ matrix.rust }} toolchain
         uses: actions-rs/toolchain@v1
@@ -64,6 +62,23 @@ jobs:
           target: ${{ matrix.target }}
           override: true
 
+      - name: Copy test languages.toml
+        run: cp .github/workflows/languages.toml ./languages.toml
+
+      - name: Download test tree-sitter grammar
+        uses: actions-rs/cargo@v1
+        with:
+          use-cross: ${{ matrix.cross }}
+          command: run
+          args: --release --locked --target ${{ matrix.target }} -- --fetch-grammars
+
+      - name: Build test tree-sitter grammar
+        uses: actions-rs/cargo@v1
+        with:
+          use-cross: ${{ matrix.cross }}
+          command: run
+          args: --release --locked --target ${{ matrix.target }} -- --build-grammars
+
       - name: Run cargo test
         uses: actions-rs/cargo@v1
         with:
@@ -71,6 +86,9 @@ jobs:
           command: test
           args: --release --locked --target ${{ matrix.target }}
 
+      - name: Restore languages.toml
+        run: git checkout languages.toml
+
       - name: Build release binary
         uses: actions-rs/cargo@v1
         with:
@@ -114,14 +132,8 @@ jobs:
     steps:
       - name: Checkout sources
         uses: actions/checkout@v2
-        with:
-          submodules: false
 
       - uses: actions/download-artifact@v2
-        # with:
-        #   path: dist
-      # - run: ls -al ./dist
-      - run: ls -al bins-*
 
       - name: Calculate tag name
         run: |
diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs
index 6ed0a7af70da5..1e6d8f3750d48 100644
--- a/helix-core/src/syntax.rs
+++ b/helix-core/src/syntax.rs
@@ -1935,14 +1935,10 @@ mod test {
         let language = get_language(&crate::RUNTIME_DIR, "Rust").unwrap();
         let config = HighlightConfiguration::new(
             language,
-            &std::fs::read_to_string(
-                "../helix-syntax/languages/tree-sitter-rust/queries/highlights.scm",
-            )
-            .unwrap(),
-            &std::fs::read_to_string(
-                "../helix-syntax/languages/tree-sitter-rust/queries/injections.scm",
-            )
-            .unwrap(),
+            &std::fs::read_to_string("../runtime/grammars/sources/rust/queries/highlights.scm")
+                .unwrap(),
+            &std::fs::read_to_string("../runtime/grammars/sources/rust/queries/injections.scm")
+                .unwrap(),
             "", // locals.scm
         )
         .unwrap();