diff --git a/.gitignore b/.gitignore
index b23d2943a3..813f86f3b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 npm-debug.log
 
-/build/
+/build/node_modules/
+
 /docs/api/
 /website/build/
 node_modules/
diff --git a/build/__tests__/react-router-dom-test.js b/build/__tests__/react-router-dom-test.js
new file mode 100644
index 0000000000..81e2df36ef
--- /dev/null
+++ b/build/__tests__/react-router-dom-test.js
@@ -0,0 +1,25 @@
+const expected = {
+  BrowserRouter: expect.any(Function),
+  // from react-router
+  Router: expect.any(Function),
+  Route: expect.any(Function),
+  Routes: expect.any(Function),
+  MemoryRouter: expect.any(Function),
+  Outlet: expect.any(Function),
+  useRoutes: expect.any(Function),
+  useParams: expect.any(Function),
+  useResolvedPath: expect.any(Function),
+  useOutlet: expect.any(Function),
+  useOutletContext: expect.any(Function),
+};
+
+describe("react-router-dom", () => {
+  it("requires", () => {
+    expect(require("react-router-dom")).toMatchObject(expected);
+  });
+
+  // TODO: Uncomment this when jest support for esm imports is finalized
+  // it("imports", () => {
+  //   return expect(import("react-router-dom")).resolves.toMatchObject(expected);
+  // });
+});
diff --git a/build/__tests__/react-router-test.js b/build/__tests__/react-router-test.js
new file mode 100644
index 0000000000..18d517fc07
--- /dev/null
+++ b/build/__tests__/react-router-test.js
@@ -0,0 +1,23 @@
+const expected = {
+  Router: expect.any(Function),
+  Route: expect.any(Function),
+  Routes: expect.any(Function),
+  MemoryRouter: expect.any(Function),
+  Outlet: expect.any(Function),
+  useRoutes: expect.any(Function),
+  useParams: expect.any(Function),
+  useResolvedPath: expect.any(Function),
+  useOutlet: expect.any(Function),
+  useOutletContext: expect.any(Function),
+};
+
+describe("react-router", () => {
+  it("requires", () => {
+    expect(require("react-router")).toMatchObject(expected);
+  });
+
+  // TODO: Uncomment this when jest support for esm imports is finalized
+  // it("imports", () => {
+  //   return expect(import("react-router")).resolves.toMatchObject(expected);
+  // });
+});
diff --git a/build/jest.config.js b/build/jest.config.js
new file mode 100644
index 0000000000..d789652d5b
--- /dev/null
+++ b/build/jest.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+  testMatch: ["**/__tests__/*-test.[jt]s?(x)"]
+};
diff --git a/contributors.yml b/contributors.yml
index dc6610e349..a9946e8c02 100644
--- a/contributors.yml
+++ b/contributors.yml
@@ -24,3 +24,4 @@
 - timdorr
 - turansky
 - vijaypushkin
+- perrin4869
diff --git a/package.json b/package.json
index 114460c1d4..1fffc89972 100644
--- a/package.json
+++ b/package.json
@@ -73,7 +73,8 @@
   },
   "jest": {
     "projects": [
-      "<rootDir>/packages/*"
+      "<rootDir>/packages/*",
+      "<rootDir>/build"
     ]
   },
   "filesize": {
diff --git a/packages/react-router-dom/package.json b/packages/react-router-dom/package.json
index 2107b8e857..9588177c23 100644
--- a/packages/react-router-dom/package.json
+++ b/packages/react-router-dom/package.json
@@ -9,9 +9,24 @@
     "directory": "packages/react-router-dom"
   },
   "license": "MIT",
-  "main": "./main.js",
+  "main": "./index.cjs",
   "module": "./index.js",
   "types": "./index.d.ts",
+  "exports": {
+    ".": {
+      "types": "./index.d.ts",
+      "node": {
+        "require": "./index.cjs",
+        "import": "./index.js"
+      },
+      "default": "./index.js"
+    },
+    "./server": {
+      "require": "./server.cjs",
+      "import": "./server.js"
+    },
+    "./package.json": "./package.json"
+  },
   "unpkg": "./umd/react-router-dom.production.min.js",
   "dependencies": {
     "react-router": "6.2.1",
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index efe44cfd0e..6fbb8d135c 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -9,9 +9,20 @@
     "directory": "packages/react-router"
   },
   "license": "MIT",
-  "main": "./main.js",
+  "main": "./index.cjs",
   "module": "./index.js",
   "types": "./index.d.ts",
+  "exports": {
+    ".": {
+      "types": "./index.d.ts",
+      "node": {
+        "require": "./index.cjs",
+        "import": "./index.js"
+      },
+      "default": "./index.js"
+    },
+    "./package.json": "./package.json"
+  },
   "unpkg": "./umd/react-router.production.min.js",
   "peerDependencies": {
     "react": ">=16.8"
diff --git a/rollup.config.js b/rollup.config.js
index 592f05af28..2c7d7671f5 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -24,6 +24,29 @@ function getVersion(sourceDir) {
   return require(`./${sourceDir}/package.json`).version;
 }
 
+function addTypeModule(contents) {
+  return JSON.stringify(
+    {
+      type: "module",
+      ...JSON.parse(contents.toString())
+    },
+    null,
+    2
+  );
+}
+
+function addTypeCommonjsFile(srcDir, destDir) {
+  return copy({
+    targets: [
+      {
+        src: `${srcDir}/package.json`,
+        dest: `${destDir}/umd`,
+        transform: () => JSON.stringify({ type: "commonjs" }, null, 2)
+      }
+    ]
+  });
+}
+
 function reactRouter() {
   const SOURCE_DIR = "packages/react-router";
   const OUTPUT_DIR = "build/node_modules/react-router";
@@ -53,7 +76,11 @@ function reactRouter() {
         }),
         copy({
           targets: [
-            { src: `${SOURCE_DIR}/package.json`, dest: OUTPUT_DIR },
+            {
+              src: `${SOURCE_DIR}/package.json`,
+              dest: OUTPUT_DIR,
+              transform: addTypeModule
+            },
             { src: `${SOURCE_DIR}/README.md`, dest: OUTPUT_DIR },
             { src: "LICENSE.md", dest: OUTPUT_DIR },
           ],
@@ -200,11 +227,13 @@ function reactRouter() {
     {
       input: `${SOURCE_DIR}/node-main.js`,
       output: {
-        file: `${OUTPUT_DIR}/main.js`,
+        file: `${OUTPUT_DIR}/index.cjs`,
         format: "cjs",
         banner: createBanner("React Router", version),
       },
-      plugins: [].concat(PRETTY ? prettier({ parser: "babel" }) : []),
+      plugins: [addTypeCommonjsFile(SOURCE_DIR, OUTPUT_DIR)].concat(
+        PRETTY ? prettier({ parser: "babel" }) : []
+      )
     },
   ];
 
@@ -240,7 +269,11 @@ function reactRouterDom() {
         }),
         copy({
           targets: [
-            { src: `${SOURCE_DIR}/package.json`, dest: OUTPUT_DIR },
+            {
+              src: `${SOURCE_DIR}/package.json`,
+              dest: OUTPUT_DIR,
+              transform: addTypeModule
+            },
             { src: `${SOURCE_DIR}/README.md`, dest: OUTPUT_DIR },
             { src: "LICENSE.md", dest: OUTPUT_DIR },
           ],
@@ -397,16 +430,18 @@ function reactRouterDom() {
     {
       input: `${SOURCE_DIR}/node-main.js`,
       output: {
-        file: `${OUTPUT_DIR}/main.js`,
+        file: `${OUTPUT_DIR}/index.cjs`,
         format: "cjs",
         banner: createBanner("React Router DOM", version),
       },
-      plugins: [].concat(PRETTY ? prettier({ parser: "babel" }) : []),
+      plugins: [addTypeCommonjsFile(SOURCE_DIR, OUTPUT_DIR)].concat(
+        PRETTY ? prettier({ parser: "babel" }) : []
+      ),
     },
     {
       input: `${SOURCE_DIR}/server.tsx`,
       output: {
-        file: `${OUTPUT_DIR}/server.js`,
+        file: `${OUTPUT_DIR}/server.cjs`,
         format: "cjs",
       },
       external: [
@@ -433,7 +468,7 @@ function reactRouterDom() {
     {
       input: `${SOURCE_DIR}/server.tsx`,
       output: {
-        file: `${OUTPUT_DIR}/server.mjs`,
+        file: `${OUTPUT_DIR}/server.js`,
         format: "esm",
       },
       external: [