n/no-top-level-await

Disallow await at the top level of a module

Also called node/no-top-level-await

Node.js can load an ES module with require(), but not one that uses await at its top level, or one that imports a module like that. In both cases require() throws ERR_REQUIRE_ASYNC_MODULE. For a published package, that locks out everyone who still uses CommonJS.

await, for await and await using are reported when they're outside of every function.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"n/no-top-level-await" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"n/no-top-level-await" = ["error", {
  ignoreBin = false,
}]

Examples#

example.js2 problems
import { connect } from "./db.js";

export const db = await connect();

for await (const row of db.rows()) {
  console.log(row);
}
example.jsNo problems
import { connect } from "./db.js";

let db;

export async function getDb() {
  db ??= await connect();
  return db;
}

Options#

OptionDefaultWhat it does
ignoreBinfalseSkip files that start with #!. They're run, not imported.
example.jswith { "ignoreBin": true }No problems
#!/usr/bin/env node
import { run } from "./cli.js";

await run(process.argv.slice(2));
example.js1 problem
#!/usr/bin/env node
import { run } from "./cli.js";

await run(process.argv.slice(2));

When not to use it#

In an application, or in any module that nobody loads with require(), top-level await is harmless.