9.3.1. Replace Imports Codemod (v2.11.0+)

In this chapter, you'll learn about the codemod that helps you replace imports in your codebase when upgrading to Medusa v2.11.0.

What is the Replace Imports Codemod?#

Medusa v2.11.0 optimized the package structure by consolidating several external packages into the @medusajs/framework package.

Previously, you had to install and manage packages related to MikroORM, Awilix, OpenTelemetry, and the pg package separately in your Medusa application. Starting with v2.11.0, these packages are included in the @medusajs/framework package.

For example, instead of importing @mikro-orm/core, you now import it from @medusajs/framework/mikro-orm/core. This applies to all of the following packages:

  • @mikro-orm/* packages (for example, @mikro-orm/core, @mikro-orm/migrations, etc.) -> @medusajs/framework/mikro-orm/{subpath}
  • awilix -> @medusajs/framework/awilix
  • pg -> @medusajs/framework/pg
  • @opentelemetry/instrumentation-pg -> @medusajs/framework/opentelemetry/instrumentation-pg
  • @opentelemetry/resources -> @medusajs/framework/opentelemetry/resources
  • @opentelemetry/sdk-node -> @medusajs/framework/opentelemetry/sdk-node
  • @opentelemetry/sdk-trace-node -> @medusajs/framework/opentelemetry/sdk-trace-node

To help you update your codebase to reflect these changes, Medusa provides a codemod that automatically replaces imports of these packages throughout your codebase.


Using the Replace Imports Codemod#

To use the replace imports codemod, create the file replace-imports.js in the root of your Medusa application with the following content:

Code
1#!/usr/bin/env node2
3const fs = require("fs")4const path = require("path")5const { execSync } = require("child_process")6
7/**8 * Script to replace imports and require statements from mikro-orm/{subpath}, awilix, and pg9 * to their @medusajs/framework equivalents10 */11
12// Define the replacement mappings13const replacements = [14  // MikroORM imports - replace mikro-orm/{subpath} with @medusajs/framework/mikro-orm/{subpath}15  {16    pattern: /from\s+['"]@?mikro-orm\/([^'"]+)['"]/g,17    // eslint-disable-next-line quotes18    replacement: 'from "@medusajs/framework/mikro-orm/$1"',19  },20  // Awilix imports - replace awilix with @medusajs/framework/awilix21  {22    pattern: /from\s+['"]awilix['"]/g,23    // eslint-disable-next-line quotes24    replacement: 'from "@medusajs/framework/awilix"',25  },26  // PG imports - replace pg with @medusajs/framework/pg27  {28    pattern: /from\s+['"]pg['"]/g,29    // eslint-disable-next-line quotes30    replacement: 'from "@medusajs/framework/pg"',31  },32  // OpenTelemetry imports - replace @opentelemetry/instrumentation-pg, @opentelemetry/resources, 33  // @opentelemetry/sdk-node, and @opentelemetry/sdk-trace-node with @medusajs/framework/opentelemetry/{subpath}34  {35    pattern: /from\s+['"]@?opentelemetry\/(instrumentation-pg|resources|sdk-node|sdk-trace-node)['"]/g,36    // eslint-disable-next-line quotes37    replacement: 'from "@medusajs/framework/opentelemetry/$1"',38  },39  // MikroORM require statements - replace require('@?mikro-orm/{subpath}') with require('@medusajs/framework/mikro-orm/{subpath}')40  {41    pattern: /require\s*\(\s*['"]@?mikro-orm\/([^'"]+)['"]\s*\)/g,42    // eslint-disable-next-line quotes43    replacement: 'require("@medusajs/framework/mikro-orm/$1")',44  },45  // Awilix require statements - replace require('awilix') with require('@medusajs/framework/awilix')46  {47    pattern: /require\s*\(\s*['"]awilix['"]\s*\)/g,48    // eslint-disable-next-line quotes49    replacement: 'require("@medusajs/framework/awilix")',50  },51  // PG require statements - replace require('pg') with require('@medusajs/framework/pg')52  {53    pattern: /require\s*\(\s*['"]pg['"]\s*\)/g,54    // eslint-disable-next-line quotes55    replacement: 'require("@medusajs/framework/pg")',56  },57  // OpenTelemetry require statements - replace require('@opentelemetry/instrumentation-pg'), 58  // require('@opentelemetry/resources'), require('@opentelemetry/sdk-node'), and 59  // require('@opentelemetry/sdk-trace-node') with require('@medusajs/framework/opentelemetry/{subpath}')60  {61    pattern: /require\s*\(\s*['"]@?opentelemetry\/(instrumentation-pg|resources|sdk-node|sdk-trace-node)['"]\s*\)/g,62    // eslint-disable-next-line quotes63    replacement: 'require("@medusajs/framework/opentelemetry/$1")',64  },65]66
67function processFile(filePath) {68  try {69    const content = fs.readFileSync(filePath, "utf8")70    let modifiedContent = content71    let wasModified = false72
73    replacements.forEach(({ pattern, replacement }) => {74      const newContent = modifiedContent.replace(pattern, replacement)75      if (newContent !== modifiedContent) {76        wasModified = true77        modifiedContent = newContent78      }79    })80
81    if (wasModified) {82      fs.writeFileSync(filePath, modifiedContent)83      console.log(`✓ Updated: ${filePath}`)84      return true85    }86
87    return false88  } catch (error) {89    console.error(`✗ Error processing ${filePath}:`, error.message)90    return false91  }92}93
94function getTargetFiles() {95  try {96    // Get the current script's filename to exclude it from processing97    const currentScript = path.basename(__filename)98    99    // Find TypeScript/JavaScript files, excluding common directories that typically don't contain target imports100    const findCommand = `find . -name node_modules -prune -o -name .git -prune -o -name dist -prune -o -name build -prune -o -name coverage -prune -o -name "*.ts" -print -o -name "*.js" -print -o -name "*.tsx" -print -o -name "*.jsx" -print`101    const files = execSync(findCommand, {102      encoding: "utf8",103      maxBuffer: 50 * 1024 * 1024, // 50MB buffer104    })105      .split("\n")106      .filter((line) => line.trim())107
108    console.log(files)109
110    const targetFiles = []111    let processedCount = 0112
113    console.log(`📄 Scanning ${files.length} files for target imports and require statements...`)114
115    for (const file of files) {116      try {117        // Skip the current script file118        const fileName = path.basename(file)119        if (fileName === currentScript) {120          processedCount++121          continue122        }123        const content = fs.readFileSync(file, "utf8")124        if (125          /from\s+['"]@?mikro-orm\//.test(content) ||126          /from\s+['"]awilix['"]/.test(content) ||127          /from\s+['"]pg['"]/.test(content) ||128          /require\s*\(\s*['"]@?mikro-orm\//.test(content) ||129          /require\s*\(\s*['"]awilix['"]/.test(content) ||130          /require\s*\(\s*['"]pg['"]/.test(content)131        ) {132          targetFiles.push(file.startsWith("./") ? file.slice(2) : file)133        }134        processedCount++135        if (processedCount % 100 === 0) {136          process.stdout.write(137            `\r📄 Processed ${processedCount}/${files.length} files...`138          )139        }140      } catch (fileError) {141        // Skip files that can't be read142        continue143      }144    }145
146    if (processedCount > 0) {147      console.log(`\r📄 Processed ${processedCount} files.                    `)148    }149
150    return targetFiles151  } catch (error) {152    console.error("Error finding target files:", error.message)153    return []154  }155}156
157function main() {158  console.log("🔄 Finding files with target imports and require statements...")159
160  const targetFiles = getTargetFiles()161
162  if (targetFiles.length === 0) {163    console.log("ℹ️  No files found with target imports or require statements.")164    return165  }166
167  console.log(`📁 Found ${targetFiles.length} files to process`)168
169  let modifiedCount = 0170  let errorCount = 0171
172  targetFiles.forEach((filePath) => {173    const fullPath = path.resolve(filePath)174    if (fs.existsSync(fullPath)) {175      if (processFile(fullPath)) {176        modifiedCount++177      }178    } else {179      console.warn(`⚠️  File not found: ${filePath}`)180      errorCount++181    }182  })183
184  console.log("\n📊 Summary:")185  console.log(`   Files processed: ${targetFiles.length}`)186  console.log(`   Files modified: ${modifiedCount}`)187  console.log(`   Errors: ${errorCount}`)188
189  if (modifiedCount > 0) {190    console.log("\n✅ Import replacement completed successfully!")191    console.log("\n💡 Next steps:")192    console.log("   1. Review the changes with: git diff")193    console.log("   2. Run your tests to ensure everything works correctly")194    console.log("   3. Commit the changes if you're satisfied")195  } else {196    console.log(197      "\n✅ No modifications needed - all imports are already correct!"198    )199  }200}201
202// Run if called directly203if (require.main === module) {204  main()205}206
207module.exports = { processFile, getTargetFiles, main }

This script scans your project for files that import from mikro-orm/{subpath}, awilix, or pg, and replaces those imports with their new equivalents from @medusajs/framework. It handles both ES module import statements and CommonJS require statements in JavaScript and TypeScript files.

Next, run the following command in your terminal to make the script executable:

Windows Users: You can run the script using node without changing permissions.
Terminal
chmod +x replace-imports.js

Finally, execute the script with the following command:

Terminal
node replace-imports.js

This will scan your project files, apply the necessary import replacements, and provide a summary of the changes made.


Next Steps#

After running the codemod, review the changes made to your codebase. You can use git diff to see the modifications. Additionally, run your tests to ensure everything works as expected.

If everything is working correctly, you can remove the replace-imports.js file from your project. You can also remove the following packages from your package.json, as they're now included in the @medusajs/framework package:

  • @mikro-orm/* packages (for example, @mikro-orm/core, @mikro-orm/migrations, etc.)
  • awilix
  • pg
  • @opentelemetry/instrumentation-pg
  • @opentelemetry/resources
  • @opentelemetry/sdk-node
  • @opentelemetry/sdk-trace-node
Was this chapter helpful?
Ask Anything
FAQ
What is Medusa?
How can I create a module?
How can I create a data model?
How do I create a workflow?
How can I extend a data model in the Product Module?
Recipes
How do I build a marketplace with Medusa?
How do I build digital products with Medusa?
How do I build subscription-based purchases with Medusa?
What other recipes are available in the Medusa documentation?
Chat is cleared on refresh
Line break