diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 3cfba83..d1ac36a 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -12,13 +12,15 @@ jobs:
     timeout-minutes: 30
     strategy:
       matrix:
-        os: [ubuntu-latest, macOS-latest]
+        os: [ubuntu-latest, macOS-latest, windows-latest]
         # We should test on 10.13.0 but don't due to a bug in Jest
         # https://github.com/facebook/jest/issues/9453
         node-version: [10.15.0, 14.x]
         exclude:
           - os: macOS-latest
             node-version: 10.15.0
+          - os: windows-latest
+            node-version: 10.15.0
       fail-fast: false
     steps:
       - name: Git checkout
diff --git a/cypress/fixtures/package.json b/cypress/fixtures/package.json
index 0f7b11b..51a82df 100644
--- a/cypress/fixtures/package.json
+++ b/cypress/fixtures/package.json
@@ -1,10 +1,10 @@
 {
   "name": "next-on-netlify-test",
   "scripts": {
-    "build": "../../../node_modules/.bin/next build",
+    "build": "next build",
     "postbuild": "node ../../../next-on-netlify",
-    "preview": "../../../node_modules/.bin/netlify dev",
+    "preview": "netlify dev",
     "predeploy": "mkdir -p .git",
-    "deploy": "../../../node_modules/.bin/netlify deploy --json > deployment.json"
+    "deploy": "netlify deploy --json > deployment.json"
   }
 }
diff --git a/cypress/plugins/buildProject.js b/cypress/plugins/buildProject.js
index 7d3d29d..2fcb4c6 100644
--- a/cypress/plugins/buildProject.js
+++ b/cypress/plugins/buildProject.js
@@ -1,13 +1,14 @@
 const { join } = require("path");
-const { spawnSync } = require("child_process");
+const execa = require("execa");
 
 // Build the given NextJS project
 const buildProject = ({ project }, config) => {
   process.stdout.write(`Building project: ${project}...`);
 
   // Build project
-  spawnSync("npm", ["run", "build"], {
+  execa.sync("npm", ["run", "build"], {
     cwd: join(config.buildsFolder, project),
+    preferLocal: true,
   });
 
   console.log(" Done! ✅");
diff --git a/cypress/plugins/deployProject.js b/cypress/plugins/deployProject.js
index 31bf691..bc9ff39 100644
--- a/cypress/plugins/deployProject.js
+++ b/cypress/plugins/deployProject.js
@@ -1,5 +1,5 @@
 const waitOn = require("wait-on");
-const { spawn, spawnSync } = require("child_process");
+const execa = require("execa");
 const { join } = require("path");
 const getBaseUrl = require("./getBaseUrl");
 
@@ -10,9 +10,10 @@ const deployLocally = ({ project }, config) => {
   // Start server. Must start in detached mode, so that we can kill it later.
   // Otherwise, we seem unable to kill it.
   // See: https://medium.com/@almenon214/killing-processes-with-node-772ffdd19aad
-  const server = spawn("npm", ["run", "preview"], {
+  const server = execa("npm", ["run", "preview"], {
     cwd: join(config.buildsFolder, project),
     detached: true,
+    localDir: true,
   });
 
   // Set deployment
@@ -36,9 +37,9 @@ const deployOnNetlify = ({ project }, config) => {
   process.stdout.write(`Deploying project: ${project}...`);
 
   // Trigger deploy
-  const deploy = spawnSync("npm", ["run", "deploy"], {
+  const deploy = execa.sync("npm", ["run", "deploy"], {
     cwd: join(config.buildsFolder, project),
-    encoding: "utf-8",
+    localDir: true,
   });
 
   // Verify success
diff --git a/lib/helpers/getDataRouteForRoute.js b/lib/helpers/getDataRouteForRoute.js
index b661a1b..ad6640b 100644
--- a/lib/helpers/getDataRouteForRoute.js
+++ b/lib/helpers/getDataRouteForRoute.js
@@ -10,8 +10,7 @@ const buildId = fileContents.toString();
 // Return the data route for the given route
 const getDataRouteForRoute = (route) => {
   const filePath = getFilePathForRoute(route, "json");
-
-  return join("/_next", "data", buildId, filePath);
+  return `/_next/data/${buildId}${filePath}`;
 };
 
 module.exports = getDataRouteForRoute;
diff --git a/package-lock.json b/package-lock.json
index 6fdea94..ea1d42f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10807,18 +10807,69 @@
       "dev": true
     },
     "execa": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
-      "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
+      "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
       "dev": true,
       "requires": {
-        "cross-spawn": "^6.0.0",
-        "get-stream": "^4.0.0",
-        "is-stream": "^1.1.0",
-        "npm-run-path": "^2.0.0",
-        "p-finally": "^1.0.0",
-        "signal-exit": "^3.0.0",
-        "strip-eof": "^1.0.0"
+        "cross-spawn": "^7.0.0",
+        "get-stream": "^5.0.0",
+        "human-signals": "^1.1.1",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.0",
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2",
+        "strip-final-newline": "^2.0.0"
+      },
+      "dependencies": {
+        "cross-spawn": {
+          "version": "7.0.3",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+          "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+          "dev": true,
+          "requires": {
+            "path-key": "^3.1.0",
+            "shebang-command": "^2.0.0",
+            "which": "^2.0.1"
+          }
+        },
+        "get-stream": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+          "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+          "dev": true,
+          "requires": {
+            "pump": "^3.0.0"
+          }
+        },
+        "is-stream": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+          "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
+          "dev": true
+        },
+        "path-key": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+          "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+          "dev": true
+        },
+        "shebang-command": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+          "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+          "dev": true,
+          "requires": {
+            "shebang-regex": "^3.0.0"
+          }
+        },
+        "shebang-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+          "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+          "dev": true
+        }
       }
     },
     "executable": {
@@ -17540,12 +17591,20 @@
       }
     },
     "npm-run-path": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
-      "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
       "dev": true,
       "requires": {
-        "path-key": "^2.0.0"
+        "path-key": "^3.0.0"
+      },
+      "dependencies": {
+        "path-key": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+          "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+          "dev": true
+        }
       }
     },
     "npmlog": {
@@ -19548,6 +19607,21 @@
             "normalize-path": "^2.1.1"
           }
         },
+        "execa": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+          "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+          "dev": true,
+          "requires": {
+            "cross-spawn": "^6.0.0",
+            "get-stream": "^4.0.0",
+            "is-stream": "^1.1.0",
+            "npm-run-path": "^2.0.0",
+            "p-finally": "^1.0.0",
+            "signal-exit": "^3.0.0",
+            "strip-eof": "^1.0.0"
+          }
+        },
         "normalize-path": {
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
@@ -19556,6 +19630,15 @@
           "requires": {
             "remove-trailing-separator": "^1.0.1"
           }
+        },
+        "npm-run-path": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+          "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+          "dev": true,
+          "requires": {
+            "path-key": "^2.0.0"
+          }
         }
       }
     },
@@ -22193,6 +22276,32 @@
       "dev": true,
       "requires": {
         "execa": "^1.0.0"
+      },
+      "dependencies": {
+        "execa": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+          "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+          "dev": true,
+          "requires": {
+            "cross-spawn": "^6.0.0",
+            "get-stream": "^4.0.0",
+            "is-stream": "^1.1.0",
+            "npm-run-path": "^2.0.0",
+            "p-finally": "^1.0.0",
+            "signal-exit": "^3.0.0",
+            "strip-eof": "^1.0.0"
+          }
+        },
+        "npm-run-path": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+          "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+          "dev": true,
+          "requires": {
+            "path-key": "^2.0.0"
+          }
+        }
       }
     },
     "winston": {
diff --git a/package.json b/package.json
index e619d34..8d52ce9 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
   },
   "devDependencies": {
     "cypress": "^5.1.0",
+    "execa": "^4.1.0",
     "folder-hash": "^3.3.3",
     "husky": "^4.3.0",
     "jest": "^26.4.2",
diff --git a/tests/customRedirects.test.js b/tests/customRedirects.test.js
index c15c02a..74b6997 100644
--- a/tests/customRedirects.test.js
+++ b/tests/customRedirects.test.js
@@ -1,5 +1,6 @@
 // Test next-on-netlify when a custom distDir is set in next.config.js
 
+const { EOL } = require("os");
 const { parse, join } = require("path");
 const { readFileSync } = require("fs-extra");
 const buildNextApp = require("./helpers/buildNextApp");
@@ -40,10 +41,11 @@ describe("Routing", () => {
   test("includes custom redirect rules", async () => {
     // Read _redirects file
     const contents = readFileSync(
-      join(PROJECT_PATH, "out_publish", "_redirects")
+      join(PROJECT_PATH, "out_publish", "_redirects"),
+      "utf8"
     );
 
-    const redirects = contents.toString().trim().split(/\n/);
+    const redirects = contents.trim().split(EOL);
     expect(redirects[0]).toEqual("# Custom Redirect Rules");
     expect(redirects[1]).toEqual(
       "https://old.example.com/* https://new.example.com/:splat 301!"
diff --git a/tests/defaults.test.js b/tests/defaults.test.js
index 5f39218..3f1126f 100644
--- a/tests/defaults.test.js
+++ b/tests/defaults.test.js
@@ -1,6 +1,6 @@
 // Test default next-on-netlify configuration
 
-const { parse, join } = require("path");
+const { parse, join, sep } = require("path");
 const {
   existsSync,
   readdirSync,
@@ -44,28 +44,32 @@ describe("next-on-netlify", () => {
 describe("next-on-netlify", () => {
   test("builds successfully", () => {
     expect(buildOutput).toMatch("Next on Netlify");
-    expect(buildOutput).toMatch("Copying public/ folder to out_publish/");
-    expect(buildOutput).toMatch("Copying static NextJS assets to out_publish/");
     expect(buildOutput).toMatch(
-      "Setting up API endpoints as Netlify Functions in out_functions/"
+      `Copying public${sep} folder to out_publish${sep}`
     );
     expect(buildOutput).toMatch(
-      "Setting up pages with getInitialProps as Netlify Functions in out_functions/"
+      `Copying static NextJS assets to out_publish${sep}`
     );
     expect(buildOutput).toMatch(
-      "Setting up pages with getServerSideProps as Netlify Functions in out_functions/"
+      `Setting up API endpoints as Netlify Functions in out_functions${sep}`
     );
     expect(buildOutput).toMatch(
-      "Copying pre-rendered pages with getStaticProps and JSON data to out_publish/"
+      `Setting up pages with getInitialProps as Netlify Functions in out_functions${sep}`
     );
     expect(buildOutput).toMatch(
-      "Setting up pages with getStaticProps and fallback: true as Netlify Functions in out_functions/"
+      `Setting up pages with getServerSideProps as Netlify Functions in out_functions${sep}`
     );
     expect(buildOutput).toMatch(
-      "Setting up pages with getStaticProps and revalidation interval as Netlify Functions in out_functions/"
+      `Copying pre-rendered pages with getStaticProps and JSON data to out_publish${sep}`
     );
     expect(buildOutput).toMatch(
-      "Copying pre-rendered pages without props to out_publish/"
+      `Setting up pages with getStaticProps and fallback: true as Netlify Functions in out_functions${sep}`
+    );
+    expect(buildOutput).toMatch(
+      `Setting up pages with getStaticProps and revalidation interval as Netlify Functions in out_functions${sep}`
+    );
+    expect(buildOutput).toMatch(
+      `Copying pre-rendered pages without props to out_publish${sep}`
     );
     expect(buildOutput).toMatch("Setting up redirects");
     expect(buildOutput).toMatch("Success! All done!");
diff --git a/tests/fixtures/package.json b/tests/fixtures/package.json
index 8b0135a..c79fdc2 100644
--- a/tests/fixtures/package.json
+++ b/tests/fixtures/package.json
@@ -1,7 +1,7 @@
 {
   "name": "next-on-netlify-test",
   "scripts": {
-    "next-build": "../../../../node_modules/.bin/next build",
+    "next-build": "next build",
     "next-on-netlify": "node ../../../next-on-netlify"
   }
 }
diff --git a/tests/helpers/buildNextApp.js b/tests/helpers/buildNextApp.js
index 9fe4d7e..eaee609 100644
--- a/tests/helpers/buildNextApp.js
+++ b/tests/helpers/buildNextApp.js
@@ -73,7 +73,7 @@ class NextAppBuilder {
     // cache the result
     if (!existsSync(this.__cachePath)) {
       // Build the nextJS app
-      npmRun("next-build", this.__stagingPath);
+      await npmRun("next-build", this.__stagingPath);
 
       // Cache the build
       copySync(this.__stagingPath, this.__cachePath);
@@ -84,7 +84,7 @@ class NextAppBuilder {
     copySync(this.__cachePath, this.__appPath);
 
     // Run next-on-netlify
-    const { stdout } = npmRun("next-on-netlify", this.__appPath);
+    const { stdout } = await npmRun("next-on-netlify", this.__appPath);
     return stdout;
   }
 
diff --git a/tests/helpers/npmRun.js b/tests/helpers/npmRun.js
index 8d20df5..7ff3e2c 100644
--- a/tests/helpers/npmRun.js
+++ b/tests/helpers/npmRun.js
@@ -1,21 +1,18 @@
-const { spawnSync } = require("child_process");
+const execa = require("execa");
 
 // Run the given npm command from the given directory
-const npmRun = (command, fromDirectory) => {
+const npmRun = async (command, fromDirectory) => {
   // Execute the command
-  const results = spawnSync("npm", ["run", command], {
-    cwd: fromDirectory,
-    encoding: "utf-8",
-  });
-
-  // Catch errors
-  if (results.status != 0) {
-    console.log(results.stdout);
-    console.log(results.stderr);
-    throw `An error occurred during -npm run ${command}- in ${fromDirectory}`;
+  try {
+    return await execa("npm", ["run", command], {
+      cwd: fromDirectory,
+      preferLocal: true,
+    });
+  } catch (error) {
+    throw new Error(
+      `An error occurred during "npm run ${command}" in ${fromDirectory}: ${error.message}`
+    );
   }
-
-  return results;
 };
 
 module.exports = npmRun;