How it works
Extension.js chooses the profile mode in this order:- System profile mode when
profile: falseorEXTENSION_USE_SYSTEM_PROFILE=true - Explicit
profilepath (if provided) - Managed profile mode (default)
- temporary (ephemeral) by default
- persistent when
persistProfile: trueorkeepProfileChanges: true
How --profile values are read
The CLI delivers flag values as strings, so Extension.js normalizes them:
--profile=false(orprofile: falsein config) means the browser’s own default profile.--profile=truemeans the managed default, the same as leaving the option unset.- Any other string is an explicit profile path.
--profile path resolves against the project (compilation context), not your shell’s working directory. This keeps sequential runs of different projects from collapsing onto one shared profile.
Profile capabilities
Seeding with copyFromProfile
copyFromProfile copies the source directory into the managed profile before launch. The copy happens only when the target is fresh, meaning it does not exist or is empty. A persisted profile therefore seeds once, and your later changes survive every run.
Profile modes
Extension.js creates managed profiles under:
dist/extension-js/profiles/<browser>-profile/<...>
dist/extension-js/profiles/<browser>-profile/dev
brave-magenta-heron. The name is random per run, so do not hardcode it. Read the profilePath field in the session’s ready.json to find the profile a run is using.
Configure in extension.config.*
CLI usage
Use an explicit profile path directly:start and preview.
Lifecycle notes
- Extension.js creates ephemeral managed profiles for each run.
- Extension.js reuses the persistent managed profile (
dev) across runs. - Each ephemeral profile carries a
.extension-js-managed-profilemarker file. On browser exit, Extension.js removes only directories that carry the marker, so kept and explicit profiles are never reclaimed. - Extension.js also sweeps stale marked profiles on the next launch. Set
EXTENSION_TMP_PROFILE_MAX_AGE_HOURSto control the maximum age (default 12 hours). - On every Firefox launch, Extension.js deletes the profile’s
startupCachedirectory. A pinned or persisted profile can otherwise serve stale extension code across a full dev restart.
Locked Chromium profiles
Before a Chromium launch, Extension.js reads the profile’sSingletonLock artifact. A lock that names a dead process or another host is stale. Extension.js removes the stale SingletonLock, SingletonSocket, and SingletonCookie files and launches normally. When the owning process is still alive on this host, the launch aborts instead. The session’s ready.json is stamped with the profile_locked error code, so machine consumers never parse the error sentence.
Privacy
A managed profile is a full browser profile. It holds cookies, history, and login data from anything you do in that browser session. Extension.js writes a.gitignore with a * rule into dist/extension-js once, so profiles and session state never reach git. Do not commit or ship this directory.
Best practices
- Use managed ephemeral profiles for baseline testing: Reduces hidden state and flaky reproductions.
- Use
persistProfilefor long-lived debug sessions: Keep auth/session/devtools state between runs. - Keep custom profiles per browser family: Avoid cross-browser contamination.
- Use system profile mode intentionally: Useful for reproduction, but less isolated than managed profiles.
Next steps
- Learn more about Browser preferences.
- Learn more about Browser flags.

