← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Script Loading (defer, async, type=module)

Frontend Intermediate
debt(d3/e1/b3/t7)
d3 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'default linter catches the common case' (d3) — Lighthouse and PageSpeed Insights flag render-blocking scripts as a standard audit, surfacing the issue routinely in any perf check.

e1 Effort Remediation debt — work required to fix once spotted

Closest to 'one-line patch' (e1) — quick_fix is literally adding a defer attribute to the script tag; trivial per-tag change.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3) — script loading choices live in HTML templates/layout; affects page load behavior broadly but doesn't shape architecture, though wrong choices proliferate across templates.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7) — misconception explicitly states devs treat async and defer as interchangeable, but async breaks execution order for dependent scripts causing intermittent race conditions; also defer/async are silently ignored on inline scripts, contradicting expectations.

About DEBT scoring →

Also Known As

defer script async script script defer script async render blocking script javascript loading strategy

TL;DR

How and when browser downloads and executes JavaScript — defer, async, and type=module control whether scripts block HTML parsing and in what order they run.

Explanation

By default, a <script src='...'> in <head> pauses HTML parsing until the script downloads and executes — blocking the entire render pipeline. Three attributes change this: async downloads in parallel and executes immediately when ready (order not guaranteed); defer downloads in parallel and executes after HTML is fully parsed, in source order; type='module' is deferred by default, scoped to the module, and supports static import/export. The rule of thumb: defer for app scripts that need the DOM or depend on each other, async for fully independent scripts like analytics. Inline scripts ignore both attributes — they always block. Placing scripts at the end of <body> is the old workaround; defer is the modern equivalent with better performance characteristics.

Common Misconception

async and defer are interchangeable — async executes as soon as downloaded, breaking execution order for dependent scripts; defer preserves source order and runs after DOM parsing, making it safe for scripts that depend on each other.

Why It Matters

A single render-blocking script in <head> delays First Contentful Paint by the full download and parse time of that script — on a slow connection this is hundreds of milliseconds of blank page before any content appears.

Common Mistakes

  • <script> in <head> without defer or async — blocks HTML parsing and delays render.
  • Using async on scripts that depend on each other (jQuery then a jQuery plugin) — causes intermittent race condition failures.
  • defer or async on inline scripts — both attributes are silently ignored; inline scripts always block.
  • Not adding type='module' to ES module scripts — modules are deferred by default and enable import/export and tree-shaking.

Avoid When

  • Do not use async on scripts that depend on other async scripts — execution order is not guaranteed.
  • Do not add defer or async to inline scripts — they are ignored and the script will still block.

When To Use

  • Use defer for any script that needs the DOM or has dependencies on other scripts.
  • Use async for analytics, ads, or chat widgets that are fully self-contained.
  • Use type='module' for ES module-based projects to get deferred execution and import/export support.

Code Examples

✗ Vulnerable
<!-- Blocks render — browser stops parsing HTML until jQuery downloads and runs -->
<head>
  <script src="jquery.js"></script>
  <script src="app.js"></script>
</head>
✓ Fixed
<!-- defer: parallel download, executes in order after DOM ready -->
<head>
  <script src="jquery.js" defer></script>
  <script src="app.js" defer></script>
</head>

<!-- async: only for fully independent scripts with no dependencies -->
<script src="analytics.js" async></script>

<!-- type=module: deferred, scoped, supports import/export -->
<script type="module" src="app.mjs"></script>

Added 6 Apr 2026
Views 71
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 1 ping T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Google 7 Ahrefs 5 Scrapy 5 Claude 4 SEMrush 4 PetalBot 4 Bing 3 Meta AI 2 Applebot 2 ChatGPT 1 Perplexity 1 Sogou 1 Brave Search 1
crawler 35 crawler_json 5
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
Frontend frontend The frontend is the part of a website or application that users see and interact with directly in their browser—buttons, text, images, and forms.

Every user interaction starts at the frontend. Understanding this layer helps you build interfaces people actually want to use and debug issues that only appear in the browser.

💡 If you can see it or click it, it's frontend; if it stores data or makes decisions you shouldn't expose, that belongs on the backend.

Ask Codex about Frontend →
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Add defer to all app scripts in <head>; use async only for independent analytics/tracking scripts; never leave bare <script src='...'> in <head>
📦 Applies To
html web
🔍 Detection Hints
<script src without defer or async in <head>
Auto-detectable: ✓ Yes lighthouse pagespeed-insights webhint
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line


✓ schema.org compliant