diff --git a/docs/guides/intro.md b/docs/guides/intro.md
index 00a326f93..b9a15eafd 100644
--- a/docs/guides/intro.md
+++ b/docs/guides/intro.md
@@ -124,8 +124,6 @@ const serverlessConfiguration: Serverless = {
 module.exports = serverlessConfiguration;
 ```
 
-Note: when deploying using a `serverless.ts` file, `ts-node` needs to be installed separately as a dev dependency.
-
 For the sake of simplicity, most examples in the documentation refer to the `serverless.yml` format. However, all functionalities work with the other available service file formats.
 
 ### Plugins
diff --git a/lib/configuration/read.js b/lib/configuration/read.js
index 2d8edb456..e57bd830b 100644
--- a/lib/configuration/read.js
+++ b/lib/configuration/read.js
@@ -5,63 +5,9 @@ const isPlainObject = require('type/plain-object/is');
 const path = require('path');
 const fsp = require('fs').promises;
 const yaml = require('js-yaml');
-const getRequire = require('../utils/get-require');
-const spawn = require('child-process-ext/spawn');
 const cloudformationSchema = require('@serverless/utils/cloudformation-schema');
 const ServerlessError = require('../serverless-error');
 
-const resolveTsNode = async (serviceDir) => {
-  // 1. If installed aside of a Framework, use it
-  try {
-    return getRequire(__dirname).resolve('ts-node');
-  } catch (slsDepError) {
-    if (slsDepError.code !== 'MODULE_NOT_FOUND') {
-      throw new ServerlessError(
-        `Cannot resolve "ts-node" due to: ${slsDepError.message}`,
-        'TS_NODE_RESOLUTION_ERROR'
-      );
-    }
-
-    // 2. If installed in a service, use it
-    try {
-      return getRequire(serviceDir).resolve('ts-node');
-    } catch (serviceDepError) {
-      if (serviceDepError.code !== 'MODULE_NOT_FOUND') {
-        throw new ServerlessError(
-          `Cannot resolve "ts-node" due to: ${serviceDepError.message}`,
-          'TS_NODE_IN_SERVICE_RESOLUTION_ERROR'
-        );
-      }
-
-      // 3. If installed globally, use it
-      const { stdoutBuffer } = await (async () => {
-        try {
-          return await spawn('npm', ['root', '-g']);
-        } catch (error) {
-          if (error.code !== 'ENOENT') {
-            throw new ServerlessError(
-              `Cannot resolve "ts-node" due to unexpected "npm" error: ${error.message}`,
-              'TS_NODE_NPM_RESOLUTION_ERROR'
-            );
-          }
-          throw new ServerlessError('"ts-node" not found', 'TS_NODE_NOT_FOUND');
-        }
-      })();
-      try {
-        return require.resolve(`${String(stdoutBuffer).trim()}/ts-node`);
-      } catch (globalDepError) {
-        if (globalDepError.code !== 'MODULE_NOT_FOUND') {
-          throw new ServerlessError(
-            `Cannot resolve "ts-node" due to: ${globalDepError.message}`,
-            'TS_NODE_NPM_GLOBAL_RESOLUTION_ERROR'
-          );
-        }
-        throw new ServerlessError('"ts-node" not found', 'TS_NODE_NOT_FOUND');
-      }
-    }
-  }
-};
-
 const readConfigurationFile = async (configurationPath) => {
   try {
     return await fsp.readFile(configurationPath, 'utf8');
@@ -107,30 +53,22 @@ const parseConfigurationFile = async (configurationPath) => {
         );
       }
     }
-    case '.ts': {
-      if (!process[Symbol.for('ts-node.register.instance')]) {
-        const tsNodePath = await (async () => {
-          try {
-            return await resolveTsNode(path.dirname(configurationPath));
-          } catch (error) {
-            throw new ServerlessError(
-              `Cannot parse "${path.basename(
-                configurationPath
-              )}": Resolution of "ts-node" failed with: ${error.message}`,
-              'CONFIGURATION_RESOLUTION_ERROR'
-            );
-          }
-        })();
-        try {
-          require(tsNodePath).register();
-        } catch (error) {
-          throw new ServerlessError(
-            `Cannot parse "${path.basename(
-              configurationPath
-            )}": Register of "ts-node" failed with: ${error.message}`,
-            'CONFIGURATION_RESOLUTION_ERROR'
-          );
-        }
+    case '.ts':
+    case '.mts': {
+      try {
+        const { createJiti } = require('jiti');
+        const jiti = createJiti(null, { interopDefault: true });
+
+        const content = await jiti.import(configurationPath, { default: true });
+
+        return content;
+      } catch (error) {
+        throw new ServerlessError(
+          `Cannot parse "${path.basename(configurationPath)}": Initialization error: ${
+            error && error.stack ? error.stack : error
+          }`,
+          'CONFIGURATION_INITIALIZATION_ERROR'
+        );
       }
     }
     // fallthrough
diff --git a/package.json b/package.json
index d2e656dc7..18dfc5efd 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@
     "graceful-fs": "^4.2.11",
     "https-proxy-agent": "^5.0.1",
     "is-docker": "^2.2.1",
+    "jiti": "^2.4.2",
     "js-yaml": "^4.1.0",
     "json-cycle": "^1.5.0",
     "json-refs": "^3.0.15",
diff --git a/test/unit/lib/configuration/read.test.js b/test/unit/lib/configuration/read.test.js
index 313404499..383ac5877 100644
--- a/test/unit/lib/configuration/read.test.js
+++ b/test/unit/lib/configuration/read.test.js
@@ -7,7 +7,6 @@ const { expect } = chai;
 
 const fsp = require('fs').promises;
 const fse = require('fs-extra');
-const proxyquire = require('proxyquire');
 const readConfiguration = require('../../../../lib/configuration/read');
 
 describe('test/unit/lib/configuration/read.test.js', () => {
@@ -58,7 +57,7 @@ describe('test/unit/lib/configuration/read.test.js', () => {
     expect(await readConfiguration(configurationPath)).to.deep.equal(configuration);
   });
 
-  it('should read "serverless.js"', async () => {
+  it('should read "serverless.js" as CJS', async () => {
     configurationPath = 'serverless.js';
     const configuration = {
       service: 'test-js',
@@ -68,23 +67,7 @@ describe('test/unit/lib/configuration/read.test.js', () => {
     expect(await readConfiguration(configurationPath)).to.deep.equal(configuration);
   });
 
-  it('should read "serverless.ts"', async () => {
-    await fse.ensureDir('node_modules');
-    try {
-      await fsp.writeFile('node_modules/ts-node.js', 'module.exports.register = () => null;');
-      configurationPath = 'serverless.ts';
-      const configuration = {
-        service: 'test-ts',
-        provider: { name: 'aws' },
-      };
-      await fsp.writeFile(configurationPath, `module.exports = ${JSON.stringify(configuration)}`);
-      expect(await readConfiguration(configurationPath)).to.deep.equal(configuration);
-    } finally {
-      await fse.remove('node_modules');
-    }
-  });
-
-  it('should read "serverless.cjs"', async () => {
+  it('should read "serverless.cjs" as CJS', async () => {
     configurationPath = 'serverless.cjs';
     const configuration = {
       service: 'test-js',
@@ -94,7 +77,7 @@ describe('test/unit/lib/configuration/read.test.js', () => {
     expect(await readConfiguration(configurationPath)).to.deep.equal(configuration);
   });
 
-  it('should read "serverless.mjs"', async () => {
+  it('should read "serverless.mjs" as ESM', async () => {
     configurationPath = 'serverless.mjs';
     const configuration = {
       service: 'test-js',
@@ -104,10 +87,9 @@ describe('test/unit/lib/configuration/read.test.js', () => {
     expect(await readConfiguration(configurationPath)).to.deep.equal(configuration);
   });
 
-  it('should register ts-node only if it is not already registered', async () => {
+  it('should read "serverless.ts" as CJS', async () => {
+    await fse.ensureDir('node_modules');
     try {
-      expect(process[Symbol.for('ts-node.register.instance')]).to.be.undefined;
-      process[Symbol.for('ts-node.register.instance')] = 'foo';
       configurationPath = 'serverless.ts';
       const configuration = {
         service: 'test-ts',
@@ -116,7 +98,22 @@ describe('test/unit/lib/configuration/read.test.js', () => {
       await fsp.writeFile(configurationPath, `module.exports = ${JSON.stringify(configuration)}`);
       expect(await readConfiguration(configurationPath)).to.deep.equal(configuration);
     } finally {
-      delete process[Symbol.for('ts-node.register.instance')];
+      await fse.remove('node_modules');
+    }
+  });
+
+  it('should read "serverless.ts" as ESM', async () => {
+    await fse.ensureDir('node_modules');
+    try {
+      configurationPath = 'serverless.ts';
+      const configuration = {
+        service: 'test-ts',
+        provider: { name: 'aws' },
+      };
+      await fsp.writeFile(configurationPath, `export default ${JSON.stringify(configuration)}`);
+      expect(await readConfiguration(configurationPath)).to.deep.equal(configuration);
+    } finally {
+      await fse.remove('node_modules');
     }
   });
 
@@ -179,24 +176,6 @@ describe('test/unit/lib/configuration/read.test.js', () => {
     );
   });
 
-  it('should reject TS configuration if "ts-node" is not found', async () => {
-    // Test against different service dir, to not fall into cached `require.resolve` value
-    configurationPath = 'other/serverless-errored.ts';
-    const configuration = {
-      service: 'test-ts',
-      provider: { name: 'aws' },
-    };
-    await fse.ensureFile(configurationPath);
-    await fsp.writeFile(configurationPath, `module.exports = ${JSON.stringify(configuration)}`);
-    await expect(
-      proxyquire('../../../../lib/configuration/read', {
-        'child-process-ext/spawn': async () => {
-          throw Object.assign(new Error('Not found'), { code: 'ENOENT' });
-        },
-      })(configurationPath)
-    ).to.eventually.be.rejected.and.have.property('code', 'CONFIGURATION_RESOLUTION_ERROR');
-  });
-
   it('should reject non object configuration', async () => {
     configurationPath = 'serverless.json';
     await fsp.writeFile(configurationPath, JSON.stringify([]));