diff --git a/Makefile b/Makefile
index 634eec5151dc44..600d87fd2316b2 100644
--- a/Makefile
+++ b/Makefile
@@ -615,7 +615,7 @@ doc-only: $(apidoc_dirs) $(apiassets)  ## Builds the docs with the local or the
 	if [ ! -d doc/api/assets ]; then \
 		$(MAKE) tools/doc/node_modules/js-yaml/package.json; \
 	fi;
-	@$(MAKE) $(apidocs_html) $(apidocs_json)
+	@$(MAKE) out/doc/api/all.html out/doc/api/all.json
 
 .PHONY: doc
 doc: $(NODE_EXE) doc-only
@@ -665,10 +665,12 @@ out/doc/api/%.json: doc/api/%.md tools/doc/generate.js tools/doc/json.js
 out/doc/api/%.html: doc/api/%.md tools/doc/generate.js tools/doc/html.js
 	$(call available-node, $(gen-html))
 
-out/doc/api/all.html: $(filter-out out/doc/api/all.html, $(apidocs_html)) \
-	tools/doc/allhtml.js
+out/doc/api/all.html: $(apidocs_html) tools/doc/allhtml.js
 	$(call available-node, tools/doc/allhtml.js)
 
+out/doc/api/all.json: $(apidocs_json) tools/doc/alljson.js
+	$(call available-node, tools/doc/alljson.js)
+
 .PHONY: docopen
 docopen: $(apidocs_html)
 	@$(PYTHON) -mwebbrowser file://$(PWD)/out/doc/api/all.html
diff --git a/doc/api/_toc.md b/doc/api/_toc.md
deleted file mode 100644
index e307d52ae8544e..00000000000000
--- a/doc/api/_toc.md
+++ /dev/null
@@ -1,62 +0,0 @@
-@// NB(chrisdickinson): if you move this file, be sure to update
-@// tools/doc/html.js to point at the new location.
-
-
-
-* [About these Docs](documentation.html)
-* [Usage & Example](synopsis.html)
-
-
-
-* [Assertion Testing](assert.html)
-* [Async Hooks](async_hooks.html)
-* [Buffer](buffer.html)
-* [C++ Addons](addons.html)
-* [C/C++ Addons - N-API](n-api.html)
-* [Child Processes](child_process.html)
-* [Cluster](cluster.html)
-* [Command Line Options](cli.html)
-* [Console](console.html)
-* [Crypto](crypto.html)
-* [Debugger](debugger.html)
-* [Deprecated APIs](deprecations.html)
-* [DNS](dns.html)
-* [Domain](domain.html)
-* [ECMAScript Modules](esm.html)
-* [Errors](errors.html)
-* [Events](events.html)
-* [File System](fs.html)
-* [Globals](globals.html)
-* [HTTP](http.html)
-* [HTTP/2](http2.html)
-* [HTTPS](https.html)
-* [Inspector](inspector.html)
-* [Internationalization](intl.html)
-* [Modules](modules.html)
-* [Net](net.html)
-* [OS](os.html)
-* [Path](path.html)
-* [Performance Hooks](perf_hooks.html)
-* [Process](process.html)
-* [Punycode](punycode.html)
-* [Query Strings](querystring.html)
-* [Readline](readline.html)
-* [REPL](repl.html)
-* [Stream](stream.html)
-* [String Decoder](string_decoder.html)
-* [Timers](timers.html)
-* [TLS/SSL](tls.html)
-* [Trace Events](tracing.html)
-* [TTY](tty.html)
-* [UDP/Datagram](dgram.html)
-* [URL](url.html)
-* [Utilities](util.html)
-* [V8](v8.html)
-* [VM](vm.html)
-* [Worker Threads](worker_threads.html)
-* [ZLIB](zlib.html)
-
-
-
-* [GitHub Repo & Issue Tracker](https://github.com/nodejs/node)
-* [Mailing List](https://groups.google.com/group/nodejs)
diff --git a/doc/api/all.md b/doc/api/all.md
deleted file mode 100644
index 47216b695d3351..00000000000000
--- a/doc/api/all.md
+++ /dev/null
@@ -1,50 +0,0 @@
-
-@include documentation
-@include synopsis
-@include assert
-@include async_hooks
-@include buffer
-@include addons
-@include n-api
-@include child_process
-@include cluster
-@include cli
-@include console
-@include crypto
-@include debugger
-@include deprecations
-@include dns
-@include domain
-@include esm
-@include errors
-@include events
-@include fs
-@include globals
-@include http
-@include http2
-@include https
-@include inspector
-@include intl
-@include modules
-@include net
-@include os
-@include path
-@include perf_hooks
-@include process
-@include punycode
-@include querystring
-@include readline
-@include repl
-@include stream
-@include string_decoder
-@include timers
-@include tls
-@include tracing
-@include tty
-@include dgram
-@include url
-@include util
-@include v8
-@include vm
-@include worker_threads
-@include zlib
diff --git a/doc/api/index.md b/doc/api/index.md
index 400faf6e5ed34a..0b43097bf294de 100644
--- a/doc/api/index.md
+++ b/doc/api/index.md
@@ -1 +1,64 @@
-@include _toc.md
+
+
+
+
+* [About these Docs](documentation.html)
+* [Usage & Example](synopsis.html)
+
+
+
+* [Assertion Testing](assert.html)
+* [Async Hooks](async_hooks.html)
+* [Buffer](buffer.html)
+* [C++ Addons](addons.html)
+* [C/C++ Addons - N-API](n-api.html)
+* [Child Processes](child_process.html)
+* [Cluster](cluster.html)
+* [Command Line Options](cli.html)
+* [Console](console.html)
+* [Crypto](crypto.html)
+* [Debugger](debugger.html)
+* [Deprecated APIs](deprecations.html)
+* [DNS](dns.html)
+* [Domain](domain.html)
+* [ECMAScript Modules](esm.html)
+* [Errors](errors.html)
+* [Events](events.html)
+* [File System](fs.html)
+* [Globals](globals.html)
+* [HTTP](http.html)
+* [HTTP/2](http2.html)
+* [HTTPS](https.html)
+* [Inspector](inspector.html)
+* [Internationalization](intl.html)
+* [Modules](modules.html)
+* [Net](net.html)
+* [OS](os.html)
+* [Path](path.html)
+* [Performance Hooks](perf_hooks.html)
+* [Process](process.html)
+* [Punycode](punycode.html)
+* [Query Strings](querystring.html)
+* [Readline](readline.html)
+* [REPL](repl.html)
+* [Stream](stream.html)
+* [String Decoder](string_decoder.html)
+* [Timers](timers.html)
+* [TLS/SSL](tls.html)
+* [Trace Events](tracing.html)
+* [TTY](tty.html)
+* [UDP/Datagram](dgram.html)
+* [URL](url.html)
+* [Utilities](util.html)
+* [V8](v8.html)
+* [VM](vm.html)
+* [Worker Threads](worker_threads.html)
+* [ZLIB](zlib.html)
+
+
+
+* [GitHub Repo & Issue Tracker](https://github.com/nodejs/node)
+* [Mailing List](https://groups.google.com/group/nodejs)
diff --git a/test/doctool/test-doctool-html.js b/test/doctool/test-doctool-html.js
index 0ca46c0adedfc1..a6119c16903a74 100644
--- a/test/doctool/test-doctool-html.js
+++ b/test/doctool/test-doctool-html.js
@@ -11,7 +11,6 @@ try {
 const assert = require('assert');
 const { readFile } = require('fs');
 const fixtures = require('../common/fixtures');
-const processIncludes = require('../../tools/doc/preprocess.js');
 const toHTML = require('../../tools/doc/html.js');
 
 // Test data is a list of objects with two properties.
@@ -64,15 +63,6 @@ const testData = [
       ' ' +
       'Describe Something in more detail here. 
'
   },
-  {
-    file: fixtures.path('doc_with_includes.md'),
-    html: '' +
-    'Look here!
' +
-    '' +
-    'foobar#
' +
-    'I exist and am being linked to.
'
-  },
   {
     file: fixtures.path('sample_document.md'),
     html: '- fish
- fish 
- Redfish 
' +
@@ -90,36 +80,34 @@ testData.forEach(({ file, html, analyticsId }) => {
 
   readFile(file, 'utf8', common.mustCall((err, input) => {
     assert.ifError(err);
-    processIncludes(file, input, common.mustCall((err, preprocessed) => {
-      assert.ifError(err);
 
-      toHTML(
-        {
-          input: preprocessed,
-          filename: 'foo',
-          nodeVersion: process.version,
-          analytics: analyticsId,
-        },
-        common.mustCall((err, output) => {
-          assert.ifError(err);
+    toHTML(
+      {
+        input: input,
+        filename: 'foo',
+        nodeVersion: process.version,
+        analytics: analyticsId,
+      },
+      common.mustCall((err, output) => {
+        assert.ifError(err);
 
-          const actual = output.replace(spaces, '');
-          // Assert that the input stripped of all whitespace contains the
-          // expected markup.
-          assert(actual.includes(expected));
+        const actual = output.replace(spaces, '');
+        // Assert that the input stripped of all whitespace contains the
+        // expected markup.
+        assert(actual.includes(expected));
 
-          // Testing the insertion of Google Analytics script when
-          // an analytics id is provided. Should not be present by default.
-          const scriptDomain = 'google-analytics.com';
-          if (includeAnalytics) {
-            assert(actual.includes(scriptDomain),
-                   `Google Analytics script was not present in "${actual}"`);
-          } else {
-            assert.strictEqual(actual.includes(scriptDomain), false,
-                               'Google Analytics script was present in ' +
-                               `"${actual}"`);
-          }
-        }));
-    }));
+        // Testing the insertion of Google Analytics script when
+        // an analytics id is provided. Should not be present by default.
+        const scriptDomain = 'google-analytics.com';
+        if (includeAnalytics) {
+          assert(actual.includes(scriptDomain),
+                 `Google Analytics script was not present in "${actual}"`);
+        } else {
+          assert.strictEqual(actual.includes(scriptDomain), false,
+                             'Google Analytics script was present in ' +
+                             `"${actual}"`);
+        }
+      })
+    );
   }));
 });
diff --git a/test/doctool/test-make-doc.js b/test/doctool/test-make-doc.js
index e019288f75cc1e..a11da0e97d8355 100644
--- a/test/doctool/test-make-doc.js
+++ b/test/doctool/test-make-doc.js
@@ -13,17 +13,16 @@ const path = require('path');
 
 const apiPath = path.resolve(__dirname, '..', '..', 'out', 'doc', 'api');
 const allDocs = fs.readdirSync(apiPath);
-assert.ok(allDocs.includes('_toc.html'));
+assert.ok(allDocs.includes('index.html'));
 
 const actualDocs = allDocs.filter(
   (name) => {
     const extension = path.extname(name);
-    return (extension === '.html' || extension === '.json') &&
-           name !== '_toc.html';
+    return extension === '.html' || extension === '.json';
   }
 );
 
-const toc = fs.readFileSync(path.resolve(apiPath, '_toc.html'), 'utf8');
+const toc = fs.readFileSync(path.resolve(apiPath, 'index.html'), 'utf8');
 const re = /href="([^/]+\.html)"/;
 const globalRe = new RegExp(re, 'g');
 const links = toc.match(globalRe);
@@ -32,8 +31,7 @@ assert.notStrictEqual(links, null);
 // Filter out duplicate links, leave just filenames, add expected JSON files.
 const linkedHtmls = [...new Set(links)].map((link) => link.match(re)[1]);
 const expectedJsons = linkedHtmls
-                       .map((name) => name.replace('.html', '.json'))
-                       .concat('_toc.json');
+                       .map((name) => name.replace('.html', '.json'));
 const expectedDocs = linkedHtmls.concat(expectedJsons);
 
 // Test that all the relative links in the TOC match to the actual documents.
diff --git a/test/fixtures/doc_with_includes.md b/test/fixtures/doc_with_includes.md
deleted file mode 100644
index 901bf0f1b0bf3b..00000000000000
--- a/test/fixtures/doc_with_includes.md
+++ /dev/null
@@ -1,2 +0,0 @@
-@include doc_inc_1
-@include doc_inc_2.md
diff --git a/tools/doc/allhtml.js b/tools/doc/allhtml.js
index fad530f1c44245..1c84e13d0ab79c 100644
--- a/tools/doc/allhtml.js
+++ b/tools/doc/allhtml.js
@@ -12,7 +12,7 @@ const htmlFiles = fs.readdirSync(source, 'utf8')
   .filter((name) => name.includes('.html') && name !== 'all.html');
 
 // Read the table of contents.
-const toc = fs.readFileSync(source + '/_toc.html', 'utf8');
+const toc = fs.readFileSync(source + '/index.html', 'utf8');
 
 // Extract (and concatenate) the toc and apicontent from each document.
 let contents = '';
@@ -47,11 +47,12 @@ for (const link of toc.match(//g)) {
   seen[href] = true;
 }
 
-// Replace various mentions of _toc with all.
-let all = toc.replace(/_toc\.html/g, 'all.html')
-  .replace('_toc.json', 'all.json')
-  .replace('api-section-_toc', 'api-section-all')
-  .replace('data-id="_toc"', 'data-id="all"');
+// Replace various mentions of index with all.
+let all = toc.replace(/index\.html/g, 'all.html')
+  .replace('', '')
+  .replace('index.json', 'all.json')
+  .replace('api-section-index', 'api-section-all')
+  .replace('data-id="index"', 'data-id="all"');
 
 // Clean up the title.
 all = all.replace(/.*?\| /, '');
diff --git a/tools/doc/alljson.js b/tools/doc/alljson.js
new file mode 100644
index 00000000000000..7e027f764e7efd
--- /dev/null
+++ b/tools/doc/alljson.js
@@ -0,0 +1,56 @@
+'use strict';
+
+// Build all.json by combining the miscs, modules, classes, globals, and methods
+// from the generated json files.
+
+const fs = require('fs');
+
+const source = `${__dirname}/../../out/doc/api`;
+
+// Get a list of generated API documents.
+const jsonFiles = fs.readdirSync(source, 'utf8')
+  .filter((name) => name.includes('.json') && name !== 'all.json');
+
+// Read the table of contents.
+const toc = fs.readFileSync(source + '/index.html', 'utf8');
+
+// Initialize results. Only these four data values will be collected.
+const results = {
+  miscs: [],
+  modules: [],
+  classes: [],
+  globals: [],
+  methods: []
+};
+
+// Identify files that should be skipped. As files are processed, they
+// are added to this list to prevent dupes.
+const seen = {
+  'all.json': true,
+  'index.json': true
+};
+
+// Extract (and concatenate) the selected data from each document.
+// Expand hrefs found in json to include source HTML file.
+for (const link of toc.match(//g)) {
+  const href = /href="(.*?)"/.exec(link)[1];
+  const json = href.replace('.html', '.json');
+  if (!jsonFiles.includes(json) || seen[json]) continue;
+  const data = JSON.parse(
+    fs.readFileSync(source + '/' + json, 'utf8')
+      .replace(/ {
-  if (er) throw er;
-  // Process the input for @include lines.
-  processIncludes(filename, input, next);
-});
-
-function next(er, input) {
   if (er) throw er;
   switch (format) {
     case 'json':
@@ -78,4 +71,4 @@ function next(er, input) {
     default:
       throw new Error(`Invalid format: ${format}`);
   }
-}
+});
diff --git a/tools/doc/html.js b/tools/doc/html.js
index 871a55baf4676c..0e254f1203f7a6 100644
--- a/tools/doc/html.js
+++ b/tools/doc/html.js
@@ -36,8 +36,8 @@ marked.setOptions({ renderer });
 
 const docPath = path.resolve(__dirname, '..', '..', 'doc');
 
-const gtocPath = path.join(docPath, 'api', '_toc.md');
-const gtocMD = fs.readFileSync(gtocPath, 'utf8').replace(/^@\/\/.*$/gm, '');
+const gtocPath = path.join(docPath, 'api', 'index.md');
+const gtocMD = fs.readFileSync(gtocPath, 'utf8').replace(/^/gms, '');
 const gtocHTML = marked(gtocMD).replace(
   / `