CLI reference
create-extstart configures your clone in place. Run it from
anywhere inside the clone; it finds the repo root itself. The published
copy on npm hands over to the copy that ships in the clone
(tooling/create), so flags and prompts always match the kit version
you cloned. The full walkthrough is in the
wizard guide.
pnpm create extstart [options]Options
Section titled “Options”| flag | meaning |
|---|---|
--name "My Ext" | extension name (written to site.config.ts, consumed by the manifest) |
--description "..." | one-line description |
--palette <name> | color palette of the extension and the website: ember (default), blue, violet, teal, pink, mono, or your own file in packages/ui/palettes/. Rewrites the palette import in apps/extension/assets/tailwind.css and apps/site/src/styles/global.css, and the marked colors of the checkout return and uninstall pages and the store asset templates. Applies even when it names the current palette, which brings those pages back in line (palettes) |
--backend firebase|supabase | backend stack: firebase (default on a fresh clone) or supabase. The wizard removes the other stack, and supabase also removes the uninstall survey. A re-run defaults to the stack the clone ships and refuses the one it removed (Supabase guide) |
--side-panel yes|no | no removes the side panel page and its sidePanel permission; yes keeps it. Interactive runs default to no on a fresh clone; --yes keeps what the clone has (the popup and the side panel) |
--on-page yes|no | no removes the on-page demo: the content script on every https:// page, its status card and their e2e tests, so the manifest asks for no access to websites. Interactive runs default to no on a fresh clone; --yes keeps what the clone has. It carries no wiring markers, so --on-page no works on any later run too (On-page UI) |
--sign-in when-needed|first-screen | first screen for a signed-out user: when-needed (default) opens as a guest and asks for an account in front of checkout and on features that need one; first-screen shows the sign-in form first. Writes auth.signIn in site.config.ts (when sign-in is asked) |
--billing-model <name> | billing model: subscription (default), lifetime-only, hybrid-credits, credits-only, or free. A model rewrites site.config.ts pricing and defaults the paywall recipe; free removes billing and the paywall (payments guide) |
--payments stripe|polar|paddle | payment provider (default: the clone’s, else stripe). Stripe always ships; the wizard removes the other providers’ code, and a re-run accepts only a provider the clone still ships (switch providers) |
--recipe <name> | paywall recipe: freemium, free-trial, daily-limit, credits, paid-only, or manual. Rewrites apps/extension/paywall.config.ts; ignored (with a note) on a free extension (paywall guide) |
--keep-markers | keep the module:* wiring markers so the wizard can prune again later; by default they’re stripped after the run (see below) |
--firebase | run only the Firebase setup step: no questionnaire, prune, or clean-tree requirement. Writes the project config everywhere it lives, creates the Firestore database and deploys its rules, switches on Email/Password sign-in, fills the Google client id when Google sign-in is on, and lists only the console steps still open; safe to re-run. See The Firebase project |
--firebase-project <id> | Firebase project id to use non-interactively (with --firebase --yes) |
--firebase-create | with --firebase-project: create that project. Headless runs never create cloud resources without this explicit flag |
--supabase | run only the Supabase setup step: no questionnaire, prune, or clean-tree requirement. Creates or picks a project through the Management API, writes its URL and publishable key into apps/extension/.env, applies the migrations, deploys the Edge Function, switches on the auth settings, and lists only the steps still open; safe to re-run. The token comes from supabase login, SUPABASE_ACCESS_TOKEN, or one paste. See The Supabase project |
--supabase-project <ref> | existing Supabase project ref to use non-interactively (with --supabase --yes) |
--supabase-create | create a new project non-interactively; headless runs never create cloud resources without this explicit flag. --supabase-org <slug> picks the organization when the account has several, --supabase-region <region> the region (default us-east-1) |
--payments-setup | run only the payments step: asks for the provider among the ones the clone ships (the clone’s first; --payments or --yes answers it; a provider the wizard removed stops the step with the files to copy back), stores the key in Secret Manager and fills backend/functions/.env, seeds the products, registers the webhook (Stripe by API; Polar and Paddle print the URL and store the secret you paste), deploys, runs the doctor. Waits with the upgrade link when the project is not on Blaze yet; stops with the re-run command when the key is missing. Headless (--yes) reads the key from STRIPE_SECRET_KEY, POLAR_ACCESS_TOKEN or PADDLE_API_KEY in the environment. On the Supabase stack it stores the secrets in the project (the token from the project step, supabase login, or SUPABASE_ACCESS_TOKEN), seeds, registers the webhook, and checks the API; nothing to deploy. See Payments |
--yes, -y | non-interactive: accept flags/defaults, no prompts |
--dry-run | print the full prune plan, change nothing. With --firebase, --supabase or --payments-setup it only says so: those steps have no dry run, and each is safe to rerun |
--force | run even with a dirty git working tree |
--skip-verify | skip the typecheck verify pass |
--with-tests | also run unit tests in the verify pass |
--verbose | stream every command’s output; by default each step is one line, and a failing step prints what its command said |
--help, -h | usage text |
What the answers remove
Section titled “What the answers remove”--billing-model free removes billing and the paywall; --side-panel no
removes the side panel; --on-page no removes the on-page demo; --backend removes the other stack, and
--backend supabase also removes the uninstall survey, which needs the
Firebase stack. --payments removes the providers it does not name
(Stripe always stays): their adapters, seed scripts, and, for Paddle,
the website’s /pay page. Everything else always ships.
Semantics worth knowing
Section titled “Semantics worth knowing”- Dirty-tree refusal: the wizard deletes and rewrites files, so it
requires a clean
git status; you review the result withgit diffand undo with git.--forceoverrides;--dry-runnever needs it. --yeskeeps billing, the side panel and the on-page demo unless--billing-model free,--side-panel noor--on-page nosays otherwise.- Marker cleanup is the default: after pruning, every remaining
module:*marker comment is stripped from the kept files (code stays). Pass--keep-markersif you want a second pass to still remove billing, the side panel, or the payment provider you kept; without them, a second pass keeps them and says so when an answer asks otherwise. The on-page demo has no markers, so it can always go. - A re-run starts from the clone: every question, and every headless default, is what the clone says now (palette, side panel, sign-in, plans, provider, recipe), and an answer that matches it rewrites nothing.
--billing-modeldefaults the paywall recipe (creditsfor the credit models); an explicit--recipewins.--dry-run --billing-model free --side-panel no --backend supabaseprints the largest prune plan: every file billing, the payment providers, the side panel, the Firebase stack, and the uninstall survey own.- An existing
apps/extension/.envis never overwritten by the env scaffold. The project and payments steps are the exceptions: each updates only its own lines in place, and every other line is preserved.--firebasesetsWXT_FIREBASE_HOSTING_URL,WXT_API_URL(and, if you paste one,WXT_GOOGLE_OAUTH_CLIENT_ID);--supabasesetsWXT_BACKEND,WXT_SUPABASE_URL,WXT_SUPABASE_ANON_KEYandWXT_API_URL;--payments-setupon the Supabase stack recordsPAYMENT_PROVIDER. - Exit code is non-zero when the wizard aborts, the plan is declined, or
the verify pass fails typecheck (or the unit tests, with
--with-tests), so it’s safe to use in CI.
Examples
Section titled “Examples”The full walkthrough, with prompts:
pnpm create extstartA monetized popup extension:
pnpm create extstart --yes --name "My Ext" --side-panel noA free trial, with the side panel:
pnpm create extstart --yes --name "My Ext" --side-panel yes --recipe free-trialHybrid credits, subscription plus allowance plus top-up packs (the credits recipe):
pnpm create extstart --yes --name "My Ext" --side-panel no --billing-model hybrid-creditsA free extension, no walls:
pnpm create extstart --yes --name "My Ext" --billing-model freeInteractive, create or pick a project and write its config everywhere:
pnpm create extstart --firebaseHeadless, use an existing project:
pnpm create extstart --firebase --yes --firebase-project my-ext-prodHeadless, create the project too (an explicit opt-in):
pnpm create extstart --firebase --yes --firebase-project my-ext-prod --firebase-createExplore what a prune would do; nothing changes:
pnpm create extstart --dry-run --side-panel nopnpm create extstart --dry-run --billing-model free --side-panel no