extro

Project Structure

How Extro maps your filesystem to a Chrome extension.

Extro uses one rule: every entrypoint is a file under src/app/. The location of the file determines what kind of surface it becomes.

The tree

extro.config.ts
package.json
page.tsx
PathWhat it becomes
src/app/popup/page.tsxpopup.html, the toolbar popup
src/app/popup/settings/page.tsxthe #/settings route inside the popup
src/app/popup/c/[id]/page.tsxthe dynamic #/c/:id route
src/app/options/page.tsxoptions.html, the options page
src/app/sidepanel/page.tsxsidepanel.html, Chrome's side panel
src/app/content/index.tscontent.js, a content script
src/app/background/index.tsbackground.js, the MV3 service worker

Anything outside src/app/ is just code: components, hooks, utils, libraries. Import freely.

Top-level directories

  • src/app/: surfaces and routes. The only directory with naming conventions. See Surfaces.
  • icons/: extension icons by size (16.png, 32.png, 48.png, 128.png). Whichever sizes you supply land in manifest.icons automatically.
  • public/: static files shipped to the output root with their names preserved. See Assets.
  • extro.config.ts: identity, permissions, and manifest overrides. Everything is optional. See the config reference.

What ships

Running extro build produces an output/chrome-mv3-prod/ directory:

manifest.json
popup.html
popup.js
options.html
options.js
background.js
content.js

Entry files keep deterministic, unhashed names (popup.js, background.js) because the manifest references them by exact path. Shared chunks under assets/ are hashed as usual.

Good to know

Surfaces are optional. If your extension only needs a popup and a service worker, create only those two folders. The manifest reflects what you have, nothing more.

On this page