Defer vs Async JavaScript and how this affects the Core Web Vitals
Learn when to async JavaScript and when to defer it for the best Core Web Vitals results

Defer vs Async JavaScript and how this affects the Core Web Vitals
Whenever I audit the Core Web Vitals of a client I often find that there is little distinction on a page between parser-blocking (sync), asynchronous or deferred JavaScript. That is a shame because different scripts have different optimal timings.
Last reviewed by Arjen Karel on March 2026
Table of Contents!
- Defer vs Async JavaScript and how this affects the Core Web Vitals
- In short
- 1. Synchronous JavaScript (sync)
- 2. Asynchronous JavaScript (async)
- 3. Deferred JavaScript (defer)
- 4. Module scripts
- Comparison table
- Common questions
- How async and defer affect the Core Web Vitals
- Taking it a step further: load scripts on demand
According to the 2025 Web Almanac, only 15% of mobile pages pass the render-blocking resources audit. The median page loads 22 scripts totaling over 630 KB, with 251 KB of that JavaScript going completely unused. Most sites are loading far too much JavaScript, and loading it at the wrong time.
In short
'Normal' JavaScript in the head of the page blocks the browser from parsing the HTML until it is downloaded and executed. Async scripts download in the background but execute as soon as they are ready, which can still interrupt parsing. Deferred scripts download in the background and wait until parsing is complete before executing, in document order.
Use defer for anything that touches the DOM. Use async for scripts that are completely independent (analytics, tracking pixels). Use neither (sync) only if the script must execute before the page renders. When in doubt, use defer.

1. Synchronous JavaScript (sync)
By default, scripts in the head of the page are synchronous. When the browser encounters a synchronous script it stops parsing the HTML, downloads the script, and executes it before continuing. This means no pixels get painted until all sync scripts are done. For large or slow scripts, this creates a visible delay in First Contentful Paint.
<!DOCTYPE html> <html> <head> <title>Sync JavaScript Example</title> <script src="script1.js"></script> <script src="script2.js"></script> </head> <body> <!-- Page content here --> </body> </html>
The browser must download and execute script1.js before it even starts on script2.js. Meanwhile, nothing renders. The median mobile page already has a Total Blocking Time of nearly 2 seconds in 2025. Synchronous scripts in the head make this worse.
2. Asynchronous JavaScript (async)
Adding the async attribute tells the browser to download the script in the background while it continues parsing the HTML. The script executes as soon as it finishes downloading, wherever the parser happens to be at that moment. Parsing pauses only during execution.
<!DOCTYPE html> <html> <head> <title>Async JavaScript Example</title> <script src="script1.js" async></script> <script src="script2.js" async></script> </head> <body> <!-- Page content here --> </body> </html>
Async scripts do not guarantee execution order. Whichever script finishes downloading first runs first. If script2.js depends on script1.js, async will break things unpredictably. Use async only for scripts that are completely independent of each other and the DOM.
One thing to be aware of: in Chrome, async scripts get Low network priority by default. This means the browser may start downloading them later than you expect. If you need an async script to load quickly (without blocking parsing), add fetchpriority="high".
3. Deferred JavaScript (defer)
The defer attribute also downloads the script in the background, but execution is postponed until the HTML document is fully parsed. Deferred scripts execute in document order, just before the DOMContentLoaded event fires.
<!DOCTYPE html> <html> <head> <title>Defer JavaScript Example</title> <script src="script1.js" defer></script> <script src="script2.js" defer></script> </head> <body> <!-- Page content here --> </body> </html>
Defer is the safer choice for most scripts. The DOM is fully available when the script runs, execution order is preserved, and the first paint is not blocked. The Telegraph deferred all their scripts and improved ad loading time by 4 seconds.
4. Module scripts
If you use ES modules (<script type="module">), you get defer behavior automatically. Module scripts download in the background, execute after parsing, and maintain order. Adding defer explicitly has no effect because it is already the default.
You can add async to a module script if you want it to execute as soon as its dependency graph resolves, rather than waiting for parsing to complete.
Comparison table
| Attribute | Downloads | Executes | Blocks parsing? | Order preserved? |
|---|---|---|---|---|
none (sync) |
Blocks parsing during download | Immediately after download | Yes (download + execution) | Yes |
async |
In the background | As soon as download completes | Only during execution | No |
defer |
In the background | After HTML parsing, before DOMContentLoaded | No | Yes |
type="module" |
In the background | After HTML parsing (same as defer) | No | Yes |
Common questions
What if I use both async and defer on the same tag? Async wins. The defer attribute is ignored entirely. This pattern used to exist as a fallback for IE9, but in 2026 there is no reason to use both.
Do async and defer work on inline scripts? No. Both attributes are ignored on classic inline scripts (no src). They only work on external scripts. The exception is <script type="module">, which is deferred by default even when inline.
Is defer better than putting scripts at the end of the body? Yes. A deferred script in the <head> starts downloading immediately (in parallel with HTML parsing). A script at the end of the body cannot start downloading until the parser reaches it. Defer gives you earlier discovery and later execution, which is the best of both worlds.
How async and defer affect the Core Web Vitals
Synchronous scripts directly hurt FCP because nothing paints until they finish. They also hurt LCP if the LCP element cannot render until scripts complete.
Async scripts improve FCP (the first paint is not blocked by download) but can still cause INP problems if they execute during user interaction and block the main thread.
Defer scripts give you the best paint metrics because they do not interfere with the initial render at all. The trade-off: if your page depends on JavaScript to display content (single-page apps), defer can actually delay LCP because the content does not appear until the script runs after parsing.
In CoreDash monitoring data, sites that moved all non-critical scripts from sync to defer saw their FCP improve by [CD:placeholder]ms on average.
Taking it a step further: load scripts on demand
Async and defer can speed up a page by not blocking the parser, but it is important to note that deferring scripts will not solve all your issues. For example, the largest contentful paint element is vulnerable to network and CPU competition caused by deferred and async scripts. The interaction to next paint is also affected by scripts that execute early during page load. That is why, whenever possible, you should load scripts on demand to have more control over their impact on page performance. Read how we load scripts on demand.
For a complete overview of all JavaScript loading strategies, see 16 methods to defer JavaScript. If you are dealing with the Lighthouse render-blocking resources warning, that guide covers the fix. You can also fine-tune loading with JavaScript priority levels and choose optimal script placement in the head vs footer.
17 years of fixing PageSpeed.
I have optimized platforms for some of the largest publishers and e-commerce sites in Europe. I provide the strategy, the code, and the RUM verification. Usually in 1 to 2 sprints.
View Services
