Keep development fast by using the lightest update strategy for each file change.
Need fast feedback after each file change? Extension.js chooses the safest and fastest update path automatically:
- HMR (hot module replacement) when module updates are safe
- Hard extension reload when runtime-critical assets change
- Restart required errors/warnings when entrypoint structure changes
Before evaluating reload behavior, confirm the same setup checks shown in the Extension.js devtools Confirm setup dialog:
| Setup step | Why it matters for reload/HMR |
|---|
Enable Developer mode in chrome://extensions | Ensures that extension runtime updates (including service worker changes) apply reliably during development. |
| Accept the local network access prompt for content scripts | Content-script reload workflows need this when the browser requests network permission. |
If you skip either step, reload behavior can appear inconsistent even when the build pipeline is healthy.
Reload tiers
1) Hot module replacement (fastest path)
Extension.js uses HMR when code can update without restarting the extensionβs background processes and event listeners.
Common examples:
- Scripts attached to extension HTML pages (accept updates through injected HMR wrappers)
- Background script modules in non-service-worker flows
- Scripts registered via the
userScripts API
- CSS updates in content-script/runtime wrappers where supported
2) Hard extension reload
Some file changes require reloading the extension runtime itself.
Typical hard reload triggers:
manifest.json
_locales/**.json
- Service worker/background runtime-critical changes
- Content script output changes (the Extension.js browser runner enforces extension reload for consistency)
Extension.js applies browser-specific hard reload mechanisms internally (Chromium and Firefox flows differ under the hood) but unifies behavior at the CLI level.
Why do content script filenames include hashes in dev?
Chrome aggressively caches chrome-extension:// resources. A stable filename like content-0.js can serve stale code even after a full extension reload. Extension.js appends a short build hash in development (for example, content-0.abcd1234.js). Each rebuild produces a fresh URL that bypasses the cache. Production builds use clean names.
3) Restart required (dev server)
When extension entrypoint references change (not just module contents), Extension.js reports restart-required diagnostics. This prevents you from continuing with a stale dependency graph.
Typical restart-required scenarios:
- Manifest script entrypoint list changes
- HTML entrypoint script/style references change
pages/ / scripts/ file set changes in watch mode (especially removals)
Behavior matrix
| Change type | Default behavior |
|---|
| JS/CSS module updates in existing entries | HMR where supported |
manifest.json / locales / service-worker-critical updates | Hard extension reload |
| Entrypoint structure updates (manifest lists, HTML script/style refs) | Restart required |
pages/ or scripts/ file add/remove during watch | Warning/error with restart guidance |
Reloading scripts and HTML outside the manifest
pages/ and scripts/ follow the same reload strategy as manifest-declared assets.
- Existing module updates can use hot-update paths.
- Entrypoint set changes (add/remove or reference graph changes) may require restart.
Example:
pages/
βββ extra-page.html
scripts/
βββ extra-script.js
Extension.js recognizes the /pages and /scripts folders for hot-reloading and treats each entry as a separate page or script it can reload independently.
Best practices
- Keep entrypoint references stable during active dev sessions to maximize HMR.
- Batch
manifest.json and locale edits to avoid repeated hard extension reloads.
- Use
pages/ and scripts/ for off-manifest assets, then restart when file sets or entry wiring changes.
- Treat restart required diagnostics as intentional safety checks, not transient warnings.
Next steps