Comparison

Async vs Defer Script Attribute: Loading Modes Compared

Compare how browsers handle scripts with no attribute, async, and defer. Learn when to use each mode, module defaults, and placement rules.

Async vs Defer Script Attribute: Loading Modes Compared

How you load JavaScript changes when it downloads, when it runs, and how long the browser blocks HTML parsing. The three modes below produce very different Core Web Vitals results even when the file itself is identical.

The three loading modes at a glance

ModeDownloadExecutionBlocks parserOrder preserved
<script>Immediate, blockingImmediately after downloadYes (both fetch + run)Yes
<script async>Parallel with HTMLAs soon as readyOnly during executionNo
<script defer>Parallel with HTMLAfter HTML parsing, before DOMContentLoadedNeverYes

Timeline diagram

Legend:  [H] HTML parsing   [D] JS download   [E] JS execution

No attribute (classic):
[H H H][D D D D][E E E][H H H H H H]
         ^ parser fully halted while script downloads AND runs

async:
[H H H H H H H H][E E E][H H H]
[    D D D D D D    ]
         ^ downloads alongside HTML; execution stops parsing whenever it lands

defer:
[H H H H H H H H H H H H][E E E]
[    D D D D D D    ]
         ^ downloads alongside HTML; execution waits until parsing finishes

1. No attribute: block and run

A plain <script src="app.js"> pauses HTML parsing the moment the browser hits it. Nothing after the tag renders until the file is fetched, parsed, and executed. This is why the old advice was to drop scripts just before </body>: any parser-blocking script above the fold delays First Contentful Paint and Largest Contentful Paint.

2. async: fire and forget

With async, the browser fetches the script in parallel with HTML parsing, then interrupts parsing to execute the moment the download finishes. Order is not guaranteed: if you load a.js then b.js and b.js arrives first, b.js runs first. Use async for scripts that do not depend on the DOM or on each other: analytics beacons, error trackers, ad pixels, and third-party widgets that self-contain.

3. defer: parallel download, ordered execution

defer also downloads in parallel, but execution waits until the HTML is fully parsed and runs in the order the tags appear. Deferred scripts fire right before DOMContentLoaded, so the DOM is guaranteed to exist. Use defer for application code, framework bootstraps, and anything that queries or mutates the DOM or relies on a helper loaded in an earlier tag.

type="module" is deferred by default

ES modules (<script type="module">) behave like defer automatically: they download in parallel and execute after parsing, in document order. You do not add defer to a module, and adding async switches it to async semantics. Classic scripts have no default: without async or defer, they block.

Placement: the old rule is obsolete

Because defer and modules never block the parser, you can put them back in <head> where they belong. Putting a deferred script in the head actually helps performance: the browser discovers it earlier and starts the download sooner, but execution still waits for the DOM. The "always at end of body" rule only applies to legacy parser-blocking scripts.

Which one should you use?

  • Analytics, pixels, independent third-party scripts: async. Order does not matter; earliest execution wins.
  • App bundles, jQuery plugins, anything touching the DOM or depending on another file: defer.
  • Inline critical JavaScript (feature flags, theme detection): no attribute, kept tiny, in the head. This is the one case where blocking is acceptable.
  • Modern ES modules: type="module" and let the default defer behavior handle it.

Common mistakes

  • Marking a jQuery-dependent plugin as async and getting "$ is not defined" race conditions.
  • Adding defer to an inline <script> without src. The attribute is ignored on inline scripts (except modules).
  • Using both async and defer. Older browsers used defer as a fallback; modern browsers prefer async, so ordering is lost.
  • Leaving render-blocking scripts in the head and blaming a poor LCP on the CDN.
async script defer script script loading render blocking type module html parser page speed core web vitals

Explore 300+ Free Tools

Utilko has tools for developers, writers, designers, students, and everyday users — all free, all browser-based.