script vs async vs defer
By FrontendPro Editorial Team Updated 9/26/2026
Answer
The difference is about when the browser downloads the file and when it stops parsing HTML to run it.
A plain <script> is the blocking one. The moment the parser reaches the tag it stops building the DOM, fetches the file, runs it, and only then continues. Put one in <head> and nothing renders until it finishes — the main reason scripts were traditionally placed just before </body>.
<script defer> downloads in the background while parsing continues, then runs after the HTML is fully parsed but before DOMContentLoaded. Deferred scripts keep their document order, so a library still runs before the code that uses it. This is the sane default for application code that touches the DOM.
<script async> also downloads in the background, but runs the instant it arrives — interrupting parsing at an unpredictable moment. Order is not guaranteed, so two async scripts may execute in either sequence. Use it only for standalone code that depends on nothing and that nothing depends on: analytics beacons and similar.
<script type="module"> behaves like defer by default, and its imports are resolved before it executes.
| Blocks parsing | Runs when | Order preserved | |
|---|---|---|---|
<script> | Yes, while downloading and running | Immediately, at the tag | Yes |
<script async> | Only while running | As soon as downloaded | No |
<script defer> | No | After parsing, before DOMContentLoaded | Yes |
<script type="module"> | No | Like defer, after imports resolve | Yes |
Rule of thumb: defer (or a module) for your own code, async for fire-and-forget third-party snippets, plain <script> only when something truly must run before the page paints — a theme script that prevents a flash of the wrong colour, for instance.
