Favour inline exports in JavaScript

I have always leaned to towards inlined exports in a module.

export function foo() {
	return 'bar';
}

Compared to this example where the export is at the end of the file.

export function foo() {
	return 'bar';
}

export { foo };

I think I might have heard/read at some point that someone else favoured this approach also but I cannot remember what the reasons were, anyway it reinforced my preference and I have stuck with it.

Recently I ran into an issue whilst refactoring that has further reinforced this preference.

Original file

The following module shows multiple exported functions listed at the end of the file.

src/utils/auth.ts

function validateToken(token: string) {
  // token validation logic
}

function generateToken(userId: string) {
  // token generation logic
}

function parseToken(token: string) {
  // token parsing logic
};

export {
  validateToken,
  generateToken,
  parseToken
};

Refactor

Later, you decide to move parseToken to its own file for improved organisation. I actually had to do this to avoid a circular dependency but that is not the main point here.

src/utils/parse-token.ts

export function parseToken(token: string) {
  // token parsing logic
}

Here is where the mistake happened. You update the original file, but keep the export list. Typescript did not complain and my IDE did not warn me. Am I missing some config to catch this?

src/utils/parse-token.ts

import { parseToken } from './parse-token';  // Imported the moved function

function validateToken(token: string) {
  // token validation logic
}

function generateToken(userId: string) {
  // token generation logic
}

export {
  validateToken,
  generateToken,
  parseToken  // 😱 Accidentally re-exporting the imported function!
};

Problem

Now other files can still import parseToken from either location:

src/services/user-service.ts

// This still works, but shouldn't!
import { parseToken } from './utils/auth';

// This is the correct import we want to enforce
import { parseToken } from './utils/parse-token';

Solution

Remove export lists entirely and use inline exports. This makes it obvious when you’re accidentally re-exporting something:

src/utils/auth.ts

import { parseToken } from './parse-token';  // Only imported for internal use

export function validateToken(token: string) {
  // token validation logic
}

export function generateToken(userId: string) {
  // token generation logic
}

// No export list = no accidental re-exports! 😊

Conclusion

My personal preference to always inline the export feels validated, I will sleep better now!

  • makes re-exports explicit and intentional
  • forces proper import updates during refactoring
  • keeps source of truth clear
  • prevents circular dependency bugs

Can inlined exports be enforced, should they be enforced? I need to check that out.