tezvyn:

Top-Level Await: `await` Without an `async` Function

AI-drafted, machine-checkedSource: developer.mozilla.orgadvanced
Top-Level Await: `await` Without an `async` Function

Top-level await lets you use `await` directly in an ES module, no `async` function needed. Use it to initialize resources like database connections on startup. The footgun: the entire module's execution blocks until the promise resolves, delaying startup.

WHY IT EXISTS Before top-level await, performing an async operation during module initialization required clumsy workarounds, like an async Immediately Invoked Function Expression (IIFE). This pattern was common for fetching configuration or connecting to a database on startup. Top-level await provides a clean, native syntax for this exact use case.

THE MENTAL MODEL Think of a module using top-level await as one big async function. When another module imports it, the JavaScript engine effectively "awaits" the completion of the module being imported. The module's execution pauses, but it does not block the main thread for other unrelated tasks.

HOW IT WORKS When the engine sees an await at the top level of an ES module, it pauses the execution of that specific module. It then works on other tasks, including loading other modules that don't depend on the paused one. Once the awaited promise settles, execution of the paused module resumes. If the promise rejects, it becomes an unhandled exception that prevents the module from loading successfully and will likely crash the application.

WHEN TO USE IT Use it for critical, one-time asynchronous setup tasks that must complete before the rest of the application can run. Three places this shows up: first, for resource initialization, like creating a database connection pool; second, for fetching essential configuration data from a remote service; third, for dynamic imports, where you need to load a module based on an async condition.

WHEN NOT TO USE IT Avoid it for non-essential tasks that can be performed lazily after startup, as it will slow down your application's boot time. Most importantly, it only works in ES modules (e.g., files with a .mjs extension or in a project with "type": "module" in package.json). It is not available in traditional CommonJS modules that use require().

ONE CANONICAL EXAMPLE Imagine a db.mjs file that sets up and exports a database connection. Another file, server.mjs, imports it. // db.mjs import { createDbConnection } from './utils'; const connection = await createDbConnection(); export default connection;

// server.mjs import db from './db.mjs'; // This code only runs after the database connection is ready. console.log('Database is ready, starting server...');

Read the original → developer.mozilla.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.