Leaderboard
Javascript Jun 27, 2026
Javascript Await Outside Async Function Error

JavaScript Top-Level Await — Does it Work Outside Async?

This is a daily Javascript challenge from the CodeShot archive. Practice your knowledge of Await Outside Async Function Error and improve your technical interview readiness.

const data = await fetch("https://api.example.com")
A It works fine in modern JS
B SyntaxError — await can only be used inside async functions (or top-level modules)
C It runs synchronously
D undefined is returned

Detailed Explanation

Why This Question Matters

If you've been writing JavaScript for a while, you've probably used async and await a thousand times. It’s the standard way to handle promises without falling into "callback hell." But there's a specific quirk in the language specification that trips up almost everyone at some point: where exactly can you actually put that await keyword?

For a long time, the rule was absolute: await must be inside an async function. If you tried to use it anywhere else, the engine would throw a SyntaxError and your code wouldn't even start running. However, as the ecosystem evolved, things changed. Understanding the nuance between "Top-Level Await" and the traditional requirement is what separates developers who just copy-paste patterns from those who actually understand the JS runtime.

Understanding the Code

Let's look at the snippet:

const data = await fetch("https://api.example.com")

At first glance, it's a simple line of code. You're calling fetch, which returns a promise, and you're telling JavaScript to pause execution until that promise resolves so you can assign the result to data.

Internally, await doesn't actually "pause" the entire JavaScript thread (which is single-threaded). Instead, it pauses the execution of that specific function or module. It yields control back to the event loop, allowing other tasks to run while the network request is pending. Once the promise settles, the engine resumes the execution of your code right where it left off.

The "catch" is the context. If this line lives inside a standard function that isn't marked as async, the engine has no way to handle the "pause and resume" logic. It doesn't know how to wrap the remaining code into a callback to be executed later, so it just crashes.

Finding the Correct Answer

In the context of this challenge, the correct answer is Option B, which typically points to the fact that using await outside an async function results in a SyntaxError—unless you are working within a JavaScript Module (ESM).

Here is the breakdown of why other assumptions fail:

  • "It will just work like a normal promise": Wrong. await is a keyword, not a method. It changes how the code is parsed. If the parser doesn't see an async wrapper or a module context, it stops immediately.
  • "It will return a Promise": This is a common point of confusion. While async functions *always* return promises, the await keyword itself is used to *unwrap* a promise. If the syntax is invalid, you don't get a promise back; you get a crash.
  • "It will run synchronously": Absolutely not. await is designed specifically to avoid blocking the main thread.
  • If you're running this in a traditional .js script file in a browser or an older Node.js environment, you'll see: SyntaxError: await is only valid in async functions and the top level of modules.

    Common Mistakes Developers Make

    The most common mistake is forgetting that async is "infectious." Once you make a function async so you can use await inside it, that function now returns a promise. This means the function *calling* that function must also handle a promise—either by using await itself or by using .then().

    Another trap is the "Top-Level Await" confusion. Modern browsers and Node.js (v14.8+) support Top-Level Await, but only in ES modules. If your package.json doesn't have "type": "module" or you aren't using the .mjs extension, trying to use await at the top of your file will still blow up.

    Many developers also try to use await inside a .forEach() loop:

    // This DOES NOT work as expected
    files.forEach(async (file) => {
      await upload(file); 
    });
    

    Because .forEach doesn't wait for the promises returned by the async callback, the loop finishes almost instantly, and your uploads happen in the background without any coordination. You should be using a for...of loop instead.

    Real-World Usage

    In production, you'll see Top-Level Await used heavily in configuration files or database initialization scripts. For example, when connecting to a database at the start of an app:

    // db.js (as a module)
    import { createConnection } from 'mysql2';
    

    // We can await the connection directly at the top level
    export const connection = await createConnection({ /* config */ });

    This is incredibly powerful because any other module that imports connection will automatically wait until the connection is established before executing its own code. It eliminates the need for messy "init" functions that you have to call manually at the start of your index.js.

    Key Takeaways

  • Context is everything. await requires an async function unless you are in a JavaScript Module.
  • SyntaxError vs. Runtime Error. Using await incorrectly is a syntax error, meaning the code won't even execute.
  • ES Modules are the key. Top-level await is a feature of ESM, not standard scripts.
  • Avoid await in forEach. Use for...of if you need to execute asynchronous tasks sequentially.
  • Async is a chain. Using await forces the containing function to be async, which in turn makes that function return a promise.
  • Why this matters

    Understanding Await Outside Async Function Error is crucial for passing technical interviews. In real-world applications, this concept often leads to subtle bugs if not handled correctly. For more details, you can always refer to the official MDN Documentation.

    📝
    Reviewed by CodeShot Editorial
    Every challenge is code-reviewed by senior developers to ensure accuracy and real-world relevance. Learn more.

    Ready for your shot?

    Join thousands of developers solving one logic puzzle every morning.

    Solve Today's Challenge →