HTML, CSS & the Browser

Defer Attribute

Definition

Written as script src="app.js" defer, it changes when a script runs rather than whether it runs. Without it the parser halts at the tag, fetches the file and executes it before reading another line of HTML. With it the download happens alongside parsing and execution waits until parsing has finished, immediately before the DOMContentLoaded event fires. Several deferred scripts keep document order, so a library tagged defer still runs before the file that depends on it. The attribute applies only to external files: defer on an inline script is ignored, as it is on a module, which already behaves this way by default.

Why It Matters

Two problems disappear at once. The script stops blocking the first paint, which on a phone is worth a few hundred milliseconds per file. And it stops running before the elements it needs exist, which is the cause of most Cannot read properties of null errors on a page somebody else wrote — the familiar workaround of moving every script tag to the bottom of the body is the same idea done by hand. Order survives too, so unlike async you can defer a whole chain of dependent files with nothing running early. The one thing to watch is that any script relying on document.write cannot be deferred at all.

How It Works

The parser meets the tag, starts the download on a separate connection and carries straight on building the DOM. Files that finish early are queued rather than run. Once parsing is complete the queue executes in document order, then DOMContentLoaded fires, then images finish and the load event follows. Because execution happens after the document is parsed, every element is present and the script can query the page directly without wrapping itself in a DOMContentLoaded listener. In practice defer is the right default for anything that touches the page, and async is right only for scripts nothing else depends on.

Real-World Example

An AI-generated dashboard uploaded to 99helpers and served at team-board.99helpers.site carries three script tags in the head, shows a blank panel on load and logs two null errors. Adding defer to all three, in the order library then helpers then app, clears both symptoms: the first paint arrives about 400 milliseconds sooner and the elements exist by the time the code goes looking for them. Nothing inside the JavaScript itself changed.

Common Mistakes

  • Adding defer to an inline script — the attribute is ignored and the code still runs the moment the parser reaches it
  • Mixing defer and async across files that depend on each other — the async one can land first and call a library that has not run yet
  • Deferring a file that an inline script calls straight away — the inline code runs during parsing, when the deferred file has not executed

Related Terms

Put a file online in seconds

Drop in a document, an image, a page or a whole static website and share the link — free, with no build step and no server to set up.

Host a file free →