Playbook
    performance
    medium

    Fix render-blocking JavaScript

    Render-blocking scripts in your <head> are holding back First Paint. Here is how to defer or async every one.

    25 minutesLast reviewed 2026-06-09

    What is happening

    Every <script src="..."> in <head> without async or defer blocks the browser from rendering the page until the script downloads and executes. Lighthouse flags these in "Eliminate render-blocking resources" — they often add 1–3 seconds to First Contentful Paint.

    Fix it

  1. Add `defer` to every `<script>` in `<head>` that does not need to run during page parsing. defer downloads the script in parallel and executes after the HTML is parsed.
  2. Use `async` for analytics and tracking pixels. async is fire-and-forget — order is not guaranteed, but the script never blocks render.
  3. Move non-critical inline scripts to the bottom of `<body>` or wrap them in a DOMContentLoaded listener.
  4. Cheat sheet

  5. <script src> → defaults to blocking. Always add defer or async.
  6. <script defer src> → downloads in parallel, runs in order, after parse. Use for app scripts.
  7. <script async src> → downloads in parallel, runs as soon as ready. Use for analytics.
  8. <script type="module" src> → defers by default. Modern modules are safe.
  9. Common gotchas

  10. jQuery before plugins. If you defer jQuery, plugins that depend on it must also defer (they will run after jQuery loads).
  11. `document.write` in deferred scripts. document.write after page parse wipes the document. Refactor or remove.
  12. Tag manager loaded sync. GTM should always be async — Google's own snippet uses async.
  13. What this doesn't do

    This is for render-blocking scripts. For unused JavaScript bytes, code-split with dynamic imports. For long tasks blocking the main thread, see Total Blocking Time fixes.