🤗 Welcome to the first article in my JavaScript ES2025 features series!
In this article, we’ll explore one of the most anticipated additions — Top-Level await
. It's a powerful upgrade that makes working with asynchronous code in JavaScript simpler and cleaner, especially inside ES modules.
📌 What Is Top-Level await
in JavaScript?
In modern JavaScript, we typically use the async/await
combo to handle asynchronous code. Until now, await
could only be used inside an async function.
Traditional Way:
const fetchData = async () => {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
};
fetchData();
With Top-Level await:
Now, with Top-Level await
, you can skip the async function wrapper and use await
directly — at the top level of your JavaScript module.
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
✅ Cleaner. Simpler. Easier to read.
📂 Where Can You Use Top-Level await ?
Top-Level await
only works inside ES modules, which means:
Your file must use the
.mjs
extension orYour project must include
"type": "module"
inpackage.json
(for Node.js)Or you're using a
tag in the browser
<script type="module">
const response = await fetch('/config.json');
const config = await response.json();
console.log(config);
</script>
🔐 Can You Use Try/Catch?
Absolutely. Error handling with Top-Level await
works just like you'd expect:
try {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
} catch (err) {
console.error("Error fetching data:", err);
}
🧠 How Top-Level await
Works Under the Hood
Although you’re writing plain await
at the top level, the JavaScript engine treats it like an async function.
(async () => {
const response = await fetch("https://api.example.com");
})();
So yes — it's still async! But now, your entire module behaves like an async function, which means:
The code execution pauses at each top-level await
Other modules importing this module will wait until it finishes
🌍 Real-World Use Case
A common scenario: You want to load a config file before initializing your app.
config.js
const res = await fetch('/config.json');
export const config = await res.json();
main.js
import { config } from './config.js';
console.log("Starting app with config:", config);
// app starts here...
This is perfect for loading runtime data like environment variables, feature flags, or user session info.
✅ Advantages of Top-Level await
💡 *Cleaner Syntax *– No need to wrap logic inside async functions
🚀 Better Flow Control – Pause execution until data is ready
📖 Improved Readability – Makes async code look like sync
❌ Disadvantages of Top-Level await
🕒 Slower Module Loading – All importing modules must wait
📦 *ESM-Only *– Doesn't work in CommonJS (require)
🧱 Blocked Execution – Overusing it can hurt performance
🎯 Final Thoughts
Top-Level await
is one of the most practical features in ES2025 — it simplifies code, improves structure, and helps you better control async flow. Just make sure to use it where it makes sense, especially in bootstrapping or initialization logic.
Thanks for reading! 🙌
If you found this useful, feel free to share it or drop your thoughts in the comments!
🔗 Connect with me on LinkedIn: linkedin.com/in/parul-verma-pv14
👉 Stay tuned — more exciting ES2025 features coming up soon!