Chrome Extension TypeScript Starter: From Zero to Chrome Web Store
What You’ll Learn
- How to structure a Chrome extension starter with TypeScript
- The minimum files needed for a Manifest V3 extension
- How to think about popup, content scripts, and service workers
- How to package the extension for the Chrome Web Store
- What to keep simple in version one
If you want a Chrome Extension TypeScript starter that can go from zero to the Chrome Web Store, the key is keeping the project small but real.
That means:
- a clear Manifest V3 setup
- one runtime role for each piece of logic
- TypeScript across the codebase
- a packaging path that does not depend on wishful thinking
The goal is not just to load the extension locally once. It is to get to something you could actually publish.
Starter Structure
Here is the shape I like:
extension/
src/
background/
index.ts
content/
index.ts
popup/
index.ts
popup.html
shared/
messages.ts
manifest.json
package.json
tsconfig.json
This is enough for a real starter.
Manifest V3 Starter
Start with a minimal but useful manifest.json:
{
"manifest_version": 3,
"name": "My TypeScript Extension",
"version": "1.0.0",
"action": {
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
},
"permissions": ["storage", "activeTab", "scripting"],
"host_permissions": ["https://*/*", "http://*/*"],
"content_scripts": [
{
"matches": ["https://*/*", "http://*/*"],
"js": ["content.js"]
}
]
}
Do not over-ask on permissions in the starter. The smaller the permission surface, the easier everything is later.
Use Shared Typed Message Contracts
This is one of the best improvements you can make early.
export type ExtensionMessage =
| { type: 'SAVE_NOTE'; payload: { text: string } }
| { type: 'GET_NOTE' };
Then your background worker can implement the contract cleanly:
chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
if (message.type === 'SAVE_NOTE') {
chrome.storage.local.set({ note: message.payload.text }).then(() => {
sendResponse({ ok: true });
});
return true;
}
if (message.type === 'GET_NOTE') {
chrome.storage.local.get('note').then((result) => {
sendResponse({ ok: true, note: result.note ?? '' });
});
return true;
}
});
This helps a lot once the extension grows beyond toy examples.
Decide What Runs Where
This is the most important architecture rule in browser extensions.
Popup
Use the popup for explicit user interaction.
Content script
Use the content script for page-aware DOM behavior.
Background service worker
Use the background worker for extension-level coordination, storage, and browser events.
If these responsibilities blur together, the extension gets messy very quickly.
Build for Local Testing First
Before you think about the Chrome Web Store, make sure the extension works through the normal local flow:
- build the files
- open
chrome://extensions - enable developer mode
- load the unpacked extension
- test the popup, content script, and background behavior
This sounds obvious, but many starter guides rush past the one part that actually tells you whether the project is shaped correctly.
Packaging for the Chrome Web Store
Once the extension works locally, the Web Store step becomes much easier.
The practical requirements are simple:
- build the final extension files
- ensure the manifest is production-ready
- verify permissions and copy are honest
- package the extension directory into a zip for upload
The exact listing details change over time, but the core engineering work does not: the extension should already be clean, permission-conscious, and easy to explain.
That is why I prefer building a small publishable starter instead of a tutorial-only demo.
Final Thought
The best Chrome Extension TypeScript starter is not the one with the most boilerplate. It is the one that gives you a clean Manifest V3 foundation, typed runtime boundaries, and a realistic path to shipping on the Chrome Web Store.
Keep the starter small, separate the responsibilities, and build something you could actually upload.
If you need help building browser extensions, TypeScript tooling, or fast product workflows that can go from prototype to release, take a look at my portfolio: voidcraft-site.vercel.app.