gh in the address bar, enter a query, and land on GitHub search results. Along the way you will wire a manifest.json and handle input in a background service worker. You will also practice the dev loop (create → dev → build) that every project follows.
What you will build
The plan
Make GitHub search as fast as a native browser shortcut. The extension reserves the keywordgh; after you type gh and a query, it opens GitHub search results.
Step 1: create the extension
Use the Extension.jscreate command to scaffold an extension named github-search.
The default template is a working sidebar starter, so the scaffold already contains
src/manifest.json and src/background.js. The next two steps replace those two files.
Everything you write in this tutorial goes in src/, because Extension.js prefers
src/manifest.json when it is present.
Using Yarn? The
yarn dlx command requires Yarn 2 or later. Yarn 1 does
not include dlx and fails with a “Command not found” error. On Yarn 1, use
the npm tab (npx) instead.Using Deno? Deno caches npm packages aggressively, including the After
@latest
tag, so npm:extension@latest can keep resolving to an older cached release.
If a scaffold or dev build fails with an error that a newer version already
fixed (for example manifest.json references files that were not emitted to disk), pin the version or refresh the cache:deno install, confirm the resolved version (extension should match
the latest release) before running deno task dev.What create generates
create scaffolds a complete project and initializes a git repository. The default template produces this tree:
tsconfig.json and extension-env.d.ts for typed extension APIs.
Two files anchor the layout:
package.jsonmarks the project root. Special folders (pages/,scripts/,public/) and thedist/output resolve from that directory, never fromsrc/.manifest.jsonmarks the extension source. It can sit at the root or insrc/. When both exist,src/manifest.jsonwins.
Step 2: create the manifest file
Every extension starts with a manifest file. It defines metadata, permissions, and runtime files. Based on the plan above, set thegh shortcut and add a service worker for user events.
Open the src/manifest.json the scaffold created and replace its contents with:
omnibox.keyword: When you typegh, the browser fires an event.background.service_worker: Listens to the event you triggered.
Step 3: create the background service worker
In browser extensions, the background service worker (a script that runs independently of any visible page) handles browser events. For this example, add a script that listens to Omnibox input and routes the query to GitHub search. Createsrc/service_worker.js, and delete the src/background.js the scaffold shipped so nothing else claims the background entry:
Step 4: load your extension
Move into the project and install its dependencies.create scaffolds the project but
does not install for you, and the dev script runs the local extension binary:
package.json file now looks like this, with extension pinned to the release you scaffolded with:
github-search as an unpacked extension, and prints a ready banner in your terminal. The Chrome address bar now recognizes gh as a keyword.
Type gh followed by a space, enter extension.js, press Enter. A new tab opens to https://github.com/search?q=extension.js&type=issues.
You now have a working browser extension that searches on GitHub.
Step 5: make it better
Improve the search experience by adding suggestions directly in the address bar with an Omnibox input listener. Updateservice_worker.js to fetch GitHub suggestions and display them while typing.
service_worker.js
Next steps
- Create another extension with templates.
- Add automated checks with Playwright E2E.
- Review Troubleshooting, Security checklist, and Performance playbook as your extension grows.

