Thesis
Most non-critical JavaScript should be deferred. But
defer changes when code runs, and timing is part of many scripts' contract. Some
scripts need to affect the page before it appears, some inline code depends on external files
being ready, and some older third-party scripts were written for a blocking world.
If defer makes pages load faster and prevents rendering bottlenecks, why is it not the default for every JavaScript file?
The answer is not that developers forgot. Script loading order is behavior—change the order and you can change the page.
The short answer
Direct answer
Not all scripts can afford to wait. Defer external scripts that are not needed for first paint; keep tiny theme, consent, or experiment bootstraps early when they prevent flicker; and refactor inline or legacy dependencies before deferring them.
A deferred external script downloads in the background, then runs after the HTML document has been parsed. That usually helps performance because the browser can keep building and painting the page instead of stopping at every script tag.
Some scripts must run before the page is visible
There are specific scenarios where you intentionally want a small script to block rendering until it finishes its job. That sounds bad in a performance audit, but it can be better than letting the page visibly change after the user has already seen it.
A/B testing
If you are testing two versions of a page, the script needs to decide which version to show before the first paint. If you defer that logic, the user may see Layout A load and then a split second later watch it jump to Layout B. That flicker is distracting, measurable, and usually worse than a tiny intentional delay.
Dark mode and theme preferences
Theme scripts often need to read a saved preference before the HTML renders. If a user prefers dark mode but the theme script is deferred, the browser may flash a bright default page before switching to the dark theme.
The flash problem
For theme, personalization, consent, and experiment scripts, the question is not only "does this block rendering?" It is also "will users see the wrong page before the correct state is applied?"
The inline script dependency problem
The defer attribute only applies to external scripts with a src attribute.
It does not make inline scripts wait.
That creates a common dependency failure:
<script src="jquery.js" defer></script>
<script>
// Inline code that expects jQuery to exist.
$(".menu").show();
</script>
Because jquery.js is deferred, the browser continues parsing the page and immediately
runs the inline script. The inline script tries to use jQuery before jQuery has executed, throws an
error, and the feature breaks.
You can fix this by moving the inline code into the deferred bundle, waiting for the right lifecycle
event, or removing the dependency entirely. But on existing sites, blindly adding defer
can expose years of hidden ordering assumptions.
Legacy code and document.write()
In the early web, a common way to inject content into a page was document.write(). You
still see it in older ad tags, widgets, and third-party snippets. The command writes HTML into the
document while the browser is reading it from top to bottom.
That timing matters. If a deferred script calls document.write() after the browser has
finished parsing the page, the browser may treat it as a write to an already-closed document. In the
worst case, it can wipe out the current page and replace it with whatever the script wrote.
Old scripts assume old loading rules
If a vendor snippet uses document.write(), do not defer it casually. Replace it with
a modern async-safe version from the vendor, or isolate it so it cannot damage the whole page.
Third-party analytics and tracking
Marketing and analytics teams often want tracking scripts to load as fast as possible. Google Analytics, Meta Pixel, heat-mapping tools, and attribution scripts are not usually needed to render the page, but they may be needed to capture the earliest user interactions.
If a visitor lands, clicks quickly, and leaves before a deferred analytics script runs, the visit or click might not be recorded. That does not mean tracking scripts should always be render-blocking. It does mean the decision is a tradeoff between performance, data completeness, privacy, and business requirements.
The modern rule: defer what you can, block what you must
You cannot defer everything, but the instinct is correct. Modern web development pushes as much JavaScript as possible out of the render-blocking path. The best sites usually have only a small amount of critical early JavaScript and defer nearly every other external file.
| Script type | Usually safe to defer? | Why |
|---|---|---|
| UI behavior after load | Yes | Menus, sliders, and non-critical interactions can usually wait until parsing is done. |
| Theme or experiment bootstrap | Often no | Users may see the wrong theme, variant, or consent state before the script runs. |
| Inline-dependent libraries | Only after refactoring | Inline code may execute before the deferred dependency is ready. |
| Legacy third-party snippets | Be careful | Older scripts may rely on blocking execution or use APIs like document.write(). |
| Analytics and pixels | Depends | Deferring improves page speed, but can miss very early exits or interactions. |
A practical checklist
- Defer external scripts that are not needed for the first paint.
- Keep tiny theme, consent, or experiment bootstraps early if they prevent visible flicker.
- Audit inline scripts before deferring the libraries they depend on.
- Replace old
document.write()snippets instead of trying to optimize around them. - Measure the business impact of analytics timing instead of treating all pixels the same.
FAQ: render-blocking vs deferred scripts
Should all JavaScript use the defer attribute?
No. Defer most non-critical external scripts, but keep early bootstraps for theme, consent, or experiments when they prevent flicker. Refactor inline dependencies and legacy snippets before deferring them.
What is the difference between render-blocking and deferred scripts?
A render-blocking script pauses HTML parsing until it downloads and runs. A deferred external script downloads in the background and runs after the document is parsed, which usually improves first paint.
Can deferring JavaScript break a website?
Yes. Inline code can run before deferred libraries it depends on, and older document.write() snippets can fail or wipe the page if they run after parsing finishes.
Should analytics scripts be deferred?
Often yes for speed, but it is a tradeoff. Deferring can miss very early clicks or exits. Measure data completeness against page-speed gains instead of treating every pixel the same.