DEV Community

Cover image for Firefox 153 Local Mode: Open Local HTML Files Over HTTPS Without a Server
Alan West
Alan West

Posted on Originally published at blog.authon.dev

Firefox 153 Local Mode: Open Local HTML Files Over HTTPS Without a Server

Firefox 153 added Local Mode to DevTools: it maps a folder on your disk to an https:// origin. You don't run npx serve or python -m http.server, and you don't touch mkcert. Open DevTools, point it at a folder, and https://shop.localhost/index.html loads straight from ~/code/shop.

The official docs pitch it in one line: "This prevents having to spawn a HTTP server to test a web page." I spent a while trying to poke holes in it. My take is that the docs oversell the HTTPS part, which localhost already gave you, and undersell per-project origins, which fix something that annoys me every day. Below is the setup, plus the limits that will send you back to Vite.

What Firefox Local Mode actually does

You register mappings. Each one has two fields:

  • Origin: a hostname Firefox serves over https://, e.g. firefox.localhost
  • Local folder: the directory the files come from, e.g. /home/alex/app

After that, https://firefox.localhost/ loads /home/alex/app/index.html and gets a proper origin instead of null or file://, with the scheme, host and storage partition the rest of the web platform expects.

The docs list two goals. One is to "test all Web APIs, including the ones being restricted to Secure Contexts (i.e. using https)". The other is "having many distinct origins (domain) for each experiment / project" with "dedicated storage/cookies for each." The second one is the reason I'd keep using it.

How to set up Local Mode (three ways)

1. The DevTools Options panel

Open DevTools (F12) and go to the Options panel (the ⋯ menu, then Settings). Add a mapping with an origin and a folder, and add as many more as you need. This is the setup for projects you come back to.

2. The file:// notification bar

Drag an HTML file into Firefox, or open any file:// URL, with DevTools open. A notification bar appears at the top of DevTools with two buttons:

  • Add To Settings opens the Options panel with a permanent mapping for that file's location already filled in.
  • Try it creates a transient mapping for the current file or folder. It disappears when you close DevTools or Firefox.

"Try it" is what I'd use for a one-off: someone sends you a zip containing a demo, you unzip it, open index.html, click once, and you're on https.

3. about:config, for teams and dotfiles

Each mapping is stored as three prefs, where N is an incrementing integer:

devtools.local-mode.mappings.N.origin    = "shop.localhost"
devtools.local-mode.mappings.N.path      = "/home/alex/code/shop"
devtools.local-mode.mappings.N.disabled  = false   (optional)
Enter fullscreen mode Exit fullscreen mode

Since they're ordinary prefs, you can put them in a profile's user.js and commit that to your dotfiles or an onboarding repo:

user_pref("devtools.local-mode.mappings.0.origin", "shop.localhost");
user_pref("devtools.local-mode.mappings.0.path", "/home/alex/code/shop");
user_pref("devtools.local-mode.mappings.1.origin", "admin.localhost");
user_pref("devtools.local-mode.mappings.1.path", "/home/alex/code/admin");
Enter fullscreen mode Exit fullscreen mode

On Lobsters, kevincox already sets Firefox prefs through Nix and half-jokingly suggested deploying static sites straight into the Firefox config. The docs say the prefs exist "so that you can easily import and transfer them between profiles, or via automation." Paths are absolute, so a shared file only works if everyone keeps their checkouts in the same location.

Do you even need HTTPS on localhost? Usually not

The headline feature is "test HTTPS-only APIs without a server," and I don't fully buy it.

http://localhost is already a secure context. MDN's Secure Contexts page lists localhost, *.localhost, 127.0.0.0/8 and ::1 as potentially trustworthy, and it lists the file scheme as well. crypto.subtle and the async clipboard API already work on npx serve at localhost:3000. On Lobsters, majaha checked and found that window.isSecureContext is true on file:// in Firefox.

So if you're on one machine and already running a server, Local Mode doesn't unlock anything you didn't have.

It's more useful in the situation the feature is named for, where you skip the server entirely. A file loaded from disk can technically count as secure and still be unusable:

  • Service workers don't register from file://. The Service Worker spec rejects any script URL whose scheme isn't http or https. Local Mode gives you https, so registration works.
  • The bigger issue is the origin. Firefox has treated local files as their own origins since the CVE-2019-11730 fix in Firefox 68, because the previous behaviour let a downloaded HTML file read its neighbours. That fix is why fetch('./data.json') from a file:// page breaks. With a mapped origin, everything in the folder shares one origin.

So Local Mode is a good fix for "open a folder and have it behave like a website," and mostly irrelevant for testing secure-context APIs, where the localhost server you already run was fine.

Per-project origins are the part worth keeping

Everybody's localhost:3000 holds leftovers from six projects. There's an auth token from last week's prototype still in localStorage and a service worker registered by some other app still intercepting requests. Somewhere in there is a cookie named session that belongs to who knows what.

They collide because the origin is http://localhost:3000 whichever project happens to be on that port. Each Local Mode mapping gets its own hostname, so shop.localhost and admin.localhost have separate storage, cookies and service worker registrations. You don't have to clear site data before switching projects, and you don't get a stale SW from another repo serving a cached index.html.

You can get the same result with a server by giving each project its own port or a *.localhost hostname in Vite. In practice almost nobody does.

Where it falls short

First, it only works while DevTools is open. The docs say so directly: "These mappings are only functional when DevTools are opened." Close the toolbox and https://shop.localhost stops resolving. For debugging that's fine. As a general way to keep a local site around, it's annoying.

Only Firefox can use it. The docs present this as a security property: no other program on your machine or network can reach the mappings. That also means no curl, no Playwright running in Chromium, and no testing from your phone. In the thread, pocket_walrus and Pomax both said they'd reach for Caddy when they need local HTTPS, and for anything beyond one browser on one machine that's still my answer too.

It also just serves files. The docs say nothing about custom response headers, SPA fallback rewrites or live reload. If your app needs Cross-Origin-Opener-Policy for SharedArrayBuffer, or /dashboard has to fall back to index.html, you need a server.

And early reports are mixed. On Lobsters, kiwec hit "failed to load" errors and a security error with the default firefox.localhost name, then went back to cloudflared tunnel. BD103 had it working for a handful of PNGs. I'd treat it as a v1 feature for now.

Local Mode vs npx serve vs Vite vs Caddy

You want to... Local Mode npx serve / python -m http.server Vite Caddy / mkcert
Open a static folder on https, no process Yes No No No
Isolate storage per project Yes, one origin each Only via separate ports Configurable Configurable
Register a service worker Yes Yes (on localhost) Yes Yes
Use TypeScript, JSX, bare imports No No Yes No
HMR / live reload No No Yes No
Custom headers (COOP/COEP) Not documented serve via serve.json; http.server no Yes Yes
Reach it from a phone or another browser No LAN, http unless you pass serve --ssl-cert LAN, http by default Yes, once the device trusts the CA
Works with DevTools closed No Yes Yes Yes

My rule after reading through all this: if the project has a build step, Local Mode isn't for it. Keep Vite. If it's a static folder (a demo, a bug repro, a vanilla JS prototype, a PWA spike, a generated docs site), stop starting a server for it. Map the folder once with "Add To Settings" and be done.

The case I'd use it for most is bug reproductions. Someone files an issue with a zip, and instead of cd, npx serve, and "wait, port 3000 is taken," you open index.html, click Try it, and you have an https origin that won't touch anything else in your browser.

Try it today

  1. Update to Firefox 153 or later (153 shipped July 21, 2026).
  2. Open any local index.html with DevTools open.
  3. Click Try it in the notification bar.
  4. Put an empty sw.js next to it, then run isSecureContext and navigator.serviceWorker.register('./sw.js') in the console.
  5. If it holds up, click Add To Settings and choose a *.localhost name per project.

How do you test HTTPS-only APIs locally right now: mkcert, Caddy, a tunnel, or push to staging and hope? And is "DevTools must stay open" a dealbreaker for you, or a fair price for never typing npx serve again?

Sources

Top comments (0)