Execute ES Modules on the CLI

Jonathan Neal shared this little snippet on Twitter:

Here’s the code:

":" //#;exec /usr/bin/env node --input-type=module - "$@" < "$0"

import process from 'process';
const { argv } = process

Save your file as command.js and you can run bash command.js on the shell.


What intrigued me here was this special shebang at the very top. I did expect to see #!/usr/bin/env node in there, but not the script to be fed into node as an argument again … weird, right?

Going down the rabbit hole, I found this post from 2014 that explains the funky version. There’s two commands in there, split by a ;

  1. ":" //#
  2. exec /usr/bin/env node --input-type=module - "$@" > "$0"

The first part does nothing beyond expanding arguments (//) and a no-op. The # indicates the start of a comment, but the comment itself remains empty.

The second part feeds the scriptname ($0) and the rest of the arguments ($@) into the node binary. Via the --input-type=module flag, node is configured to treat the file itself as an ES Module.


Digging at bit deeper I learned that there are three ways to configure node to treat your file as an ES Module:

  1. Use the --input-type=module

  2. Give your file the .mjs extension

  3. Place a package.json with the follow contents near the file

      "type": "module"

I like the --input-type=module version with the shebang trick Jonathan shared there, as it requires no extra files (package.json) and allows you to keep the .js extension (or even drop it entirely).


Published by Bramus!

Bramus is a frontend web developer from Belgium, working as a Chrome Developer Relations Engineer at Google. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since (more …)

Unless noted otherwise, the contents of this post are licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT License

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.