Skip to content
NewBun 1.4.5 is out. Release notes
AphrodyBun

Linter · Rules

n/no-top-level-await

Disallow await at the top level of a module

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

Reported:

import { connect } from "./db.js";

export const db = await connect();

for await (const row of db.rows()) {
  console.log(row);
}

Not reported:

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.
#!/usr/bin/env node
import { run } from "./cli.js";

await run(process.argv.slice(2));
#!/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.