Mateen Kiani
Published on Thu Jul 10 2025·4 min read
Writing code in separate files is a great way to keep a Node.js project organized and maintainable. Breaking your logic into modules lets you reuse components, share utilities, and simplify debugging. Yet, many developers stumble when they try to import or export functions across files, especially as Node.js supports both CommonJS and ES modules.
How do you correctly export a function in one file and import it in another? In this guide, we’ll walk through both module systems—showing you step-by-step how to share functions, avoid common pitfalls, and leverage dynamic imports for on-demand loading.
By mastering these patterns, you’ll write cleaner code, speed up development, and ensure your project structure scales smoothly. Ready to dive in?
Before we import a function, we need to export it properly. In Node.js there are two main module systems:
Create a file named mathUtils.js
:
// mathUtils.jsfunction add(a, b) {return a + b}function multiply(a, b) {return a * b}module.exports = {add,multiply,}
Here we attach add
and multiply
to module.exports
, making them available to other files.
If your project uses ES modules (set "type": "module"
in package.json
), export functions like this:
// stringUtils.jsexport function capitalize(str) {return str.charAt(0).toUpperCase() + str.slice(1)}export function lowerCase(str) {return str.toLowerCase()}
Each function gets its own export
keyword, which you can import elsewhere.
Tip: Align your export style across files to avoid confusion. Mixing CommonJS and ES Modules can lead to unexpected errors.
When using CommonJS, you bring in functions with require
.
// app.jsconst { add, multiply } = require('./mathUtils')console.log(add(2, 3)) // 5console.log(multiply(4, 5)) // 20
Notice:
.js
extension when requiring local files../mathUtils
looks in the same folder. You can use ../
to go up a level.• Always check file paths: typos in require('./utils')
will crash your app.
• Avoid circular dependencies: two files requiring each other can lead to incomplete exports.
Pro Tip: If you need to import JSON data, see how to import JSON file in Node.js for best practices.
With ES Modules, you switch to import
and export
syntax.
package.json
, add:
json
{
"type": "module"
}
.js
extensions in imports.// app.mjs or app.js (with type: module)import { capitalize, lowerCase } from './stringUtils.js'console.log(capitalize('hello')) // Helloconsole.log(lowerCase('WORLD')) // world
You can also import the default export or rename imports:
// defaultExport.jsexport default function greet(name) {return `Hello, ${name}!`}// app.jsimport greet from './defaultExport.js'import { capitalize as cap } from './stringUtils.js'console.log(greet('Alice')) // Hello, Alice!console.log(cap('bob')) // Bob
Note: ES Modules are fully supported in modern Node.js versions. Use them if you prefer standard JavaScript syntax.
Sometimes you only need a module under certain conditions. Dynamic importing can help:
// lazyLoad.jsasync function loadFeature(flag) {if (flag) {const { specialFeature } = await import('./specialFeature.js')specialFeature()} else {console.log('Feature not loaded')}}loadFeature(true)
Benefits:
Keep in mind dynamic imports return a promise, so use
await
or.then()
.
When things go wrong, here’s how to debug:
require
with import
without enabling ES modules.require('./utils')
vs import './utils.js'
.export function foo
) or added it to module.exports
.If you still get errors, add console logs at the top of your modules to see if they run at all.
Tip: Use Node’s
--trace-warnings
flag to get more details on import issues.
Importing functions from other files is a core skill for any Node.js developer. Whether you stick with CommonJS or embrace ES modules, the patterns are simple:
import()
.By modularizing your code, you’ll boost readability, enable better testing, and keep your project maintainable. Start refactoring large files into focused modules today—and enjoy cleaner, more organized code tomorrow!