Behavior of export and export default in JavaScript

I am creating a NodeJS and Express app and want a module for configuration that runs once on start up then makes a serverConfig object available to any other module that needs these values. So far I have something like this:

const loadConfig = () => {
    // logic to load configuration from environment variables, AWS Secrets Manager, etc.
}

export default loadConfig()

Now I can do

import serverConfig from 'config'

When I do this in multiple files will loadConfig() be called each time? Or will I have access to a reference to a single object from all of my imports? I only want this loadConfig() function to execute once on start up. These config values should not change during execution. And I don’t want to repeat the (perhaps) time consuming logic in loadConfig() multiple times during each request to my API.

If not, what is the correct way to call loadConfig() once on server start up and create an object that all other modules can import and reference.

>Solution :

Everything in file scope executes once. Once the exports of a file are resolved, they are directly used by reference for any subsequent imports.

Any function call that is is not inside function itself will be executed exactly once when that file is imported when your program first starts up.

// a.ts
console.log('foo')

// b.ts
import './a'

// c.ts
import './a'

// main.ts
import './b'
import './c'

If you compile and run main.ts you will get exactly one output of "foo" to the console.


Given that, your example could be rewritten as:

const loadConfig = () => {
    // logic to load configuration from environment variables, AWS Secrets Manager, etc.
}

const config = loadConfig()

export default config

Now its pretty clear that loadConfig() is called from the file scope and so only executes once.

This version:

export default loadConfig()

just avoids the intermediary variable but otherwise functions exactly the same.


If you did want to run that logic multiple times, you just need to export a function to do it for you.

// config.ts
export const loadConfig = () => {
    // ...
}

// main.ts
import { loadConfig } from './config'

loadConfig()
loadConfig() // now do it again.

That doesn’t sound like what want, but I list it here to make it clear what the difference is.

Leave a Reply