I've built several Chrome extensions over the past few years and kept running into the same problem.
Most Chrome extension templates are fine for a quick demo but fall apart when you try to build a real product.
As soon as you introduce things like:
- popup UI
- side panel UI
- content scripts
- background service workers
- message passing
- storage
- API calls
the architecture gets messy very quickly.
The first couple of extensions I built ended up with logic scattered between popup scripts, content scripts, and the background worker. It worked, but it quickly became difficult to maintain as the extension grew.
After rebuilding the same structure multiple times, I eventually settled on an architecture that works reliably for production extensions.
The Basic Architecture
The architecture that has worked best for me looks like this:

Each layer has a clear responsibility.
Content Scripts
Content scripts stay very thin and mainly extract page data.
They should avoid business logic whenever possible.
Their job is simply to interact with the webpage and send data to the extension runtime.
Background Service Worker
The background service worker becomes the central coordinator for the extension.
It typically handles:
- API calls
- authentication
- storage
- privileged extension logic
- message routing
Keeping this logic centralized prevents extension code from becoming fragmented.
UI Layer (Popup & Side Panel)
The UI layer is purely presentation.
Popup and side panel components communicate with the background worker through message passing.
This keeps UI code simple and avoids mixing extension logic with interface logic.
Example Project Structure
The project structure I now use looks like this:
src/
popup/
sidepanel/
options/
background/
content/
core/
messaging/
storage/
api/
auth/
logging/
Separating UI, extension runtime, and shared utilities makes the codebase much easier to maintain.
This structure allows the extension to grow without turning into a tangled codebase.
Why This Structure Works
A few principles made the biggest difference:
- Content scripts stay thin
- Background worker handles privileged logic
- UI stays separate from extension logic
- Shared systems live in a core layer
Once these boundaries are clear, the extension becomes much easier to reason about.
Turning This Into a Reusable Starter
After rebuilding this architecture several times, I eventually packaged it into a reusable starter kit called NeuroLaunch.
It includes:
- popup UI
- side panel UI
- background worker
- message passing layer
- storage abstraction
- API helpers
- authentication module
- example extension feature
If you're interested, you can check it out here:
https://stackfactory.gumroad.com/l/neurolaunch
The goal was simply to create a clean extension foundation so developers can focus on building features instead of rebuilding boilerplate.
Final Thoughts
Chrome extensions are deceptively simple at first.
But once you combine UI, content scripts, background workers, and APIs, the architecture matters a lot.
Hopefully this breakdown helps anyone building production Manifest V3 extensions.
I'm always interested to see how other developers structure their extension projects.
Top comments (0)