Skip to main content

await in arrow functions

Yes, you can use await inside an arrow function, but only when that arrow is declared with the async keyword. The shape of the function is irrelevant here: it is async that grants permission to use await, not the arrow or the function keyword.

Theory

TL;DR

  • await is allowed only inside an async function or at the top level of an ES module.
  • An arrow function becomes asynchronous just as easily: async () => { ... }.
  • Without async you get a SyntaxError, and the code does not run at all, because the error happens at parse time.
  • Any async function, arrow ones included, always returns a promise.
  • An async arrow can be passed as a callback, for example into .then(), and await inside it is perfectly legal.
  • Outside a function, await works only as top-level await in ESM.

Quick example

javascript
const fetchData = async () => { const data = await Promise.resolve('Done'); console.log(data); }; fetchData();

Result:

text
Done

async in front of an arrow function turns it into an asynchronous function that always returns a promise.

Where await is allowed at all

await is an operator you may use in exactly two places:

  • inside a function declared with async;
  • at the top level of a module (top-level await).

Using await outside async is a syntax error:

javascript
// Error const result = await Promise.resolve(42); // SyntaxError: await is only valid in async functions

The same goes for a plain arrow without async:

javascript
const foo = () => { const data = await Promise.resolve('value'); console.log(data); }; // SyntaxError: await is only valid in async functions

Note that this is not a runtime error. JS will not even start executing the code, because await is not permitted in a normal function, so the script fails while it is still being parsed.

What an async arrow returns

An async arrow always returns a promise, even when it contains no await at all:

javascript
const sum = async (a, b) => a + b; console.log(sum(1, 2)); // Promise { 3 }

That is the same as writing:

javascript
function sum(a, b) { return Promise.resolve(a + b); }

So the result of such a function has to be either awaited or handled through .then().

Different ways to write it

An arrow with await in its plain form:

javascript
const loadUser = async () => { const res = await fetch('/api/user'); return res.json(); };

With parameters:

javascript
const getUser = async (id) => { const res = await fetch(`/api/user/${id}`); return res.json(); };

A multi-line form:

javascript
const processData = async () => { const data = await fetch('/api/data'); const json = await data.json(); console.log(json); };

Inside a promise chain:

javascript
Promise.resolve('A') .then(async (x) => { const y = await Promise.resolve('B'); return x + y; }) .then(console.log); // "AB"

Here then() takes an async arrow function and await inside it is entirely legal: then simply waits for the promise that this function returns.

Top-level await

Modern JS modules (ESM) let you use await outside functions, as long as the code really runs as a module and not as a plain <script> without type="module":

javascript
// main.js const data = await fetch('/api/data').then(r => r.json()); console.log(data);

This is top-level await. It works only in ESM (in the browser with <script type="module">, or in Node.js with "type": "module" in package.json). In a CommonJS module such code will not run.

A simple analogy: async in front of an arrow function is a pass that gives you the right to use await inside. Without it the engine simply does not know where to deliver the awaited result.

Summary table

QuestionAnswer
Can await be used in an arrow function?Yes, if it is declared as async
What happens without async?SyntaxError: await is only valid in async functions
What does an async arrow return?Always a Promise
Can await appear in .then() or in callbacks?Yes, if the callback itself is declared async
Can await be used outside a function?Only as top-level await in modules

Common mistakes

  • Putting await in a plain arrow and being surprised that even the code before it does not run: this is a parse error, not a runtime one.
  • Forgetting that an async arrow returns a promise and writing const x = sum(1, 2), which yields a Promise instead of a number.
  • Marking the outer function async while using await inside a nested plain callback, for example arr.forEach(item => { await save(item); }). The callback itself is what needs the keyword: async item => ....
  • Expecting arr.forEach(async ...) to wait for every operation: forEach ignores the returned promises, so you need for...of with await or Promise.all(arr.map(async ...)).
  • Using top-level await in a file that is loaded as a classic script or as CommonJS, where it is simply not available.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.