Moving a site to site-kit 7
site-kit 7 is organised the way Sonor's dashboard is: one entry per module.
Most sites need no changes at all. Move a site when you next touch it;
nothing forces it before then, because a
site's ^6 range never picks up 7.
The short version
pnpm add @sonordev/site-kit@^7
npx sonor-setup codemod --check # lists what needs moving (writes nothing)
npx sonor-setup codemod --write # moves it
pnpm build # a bump you didn't build is a guessRun the codemod in each app or workspace package that imports site-kit (in a monorepo, inside each workspace package too). It's idempotent: running it twice changes nothing the second time. It works from any 2.x-6.x site: copies of sites on 4.2, 5.8 and 6.5 were migrated with it and built.
It leaves nothing in the project but the change. Since sonor-setup 7.1.2 the
originals of the files it writes go to a folder in your OS temp directory
(it prints where, and git has them too), not .bak files beside them, and
it never creates or edits .env.example: .env.local is the one env file.
An old fallback such as process.env.SONOR_API_KEY || process.env.UPTRADE_API_KEY
becomes process.env.SONOR_API_KEY.
Requirements: Next 16 and Node 20.19+ or 22.12+ (Netlify's default is 22).
What changed, and what the codemod does about it
1. The root entry is types-only
@sonordev/site-kit exports types and SITE_KIT_VERSION, nothing that runs.
A stray root import used to be able to pull commerce, signal or redirect code
into a page's bundle.
| Was | Now |
|---|---|
import { BookingWidget } from '@sonordev/site-kit' | @sonordev/site-kit/sync |
import { AffiliatesWidget, useAffiliates } from '@sonordev/site-kit' | @sonordev/site-kit/affiliates (new entry) |
| commerce components and fetchers | @sonordev/site-kit/commerce |
ManagedImage and the image helpers | @sonordev/site-kit/website/images |
SignalBridge, experiments, useSignal* | @sonordev/site-kit/signal |
TestimonialSection, fetchReviews | @sonordev/site-kit/reputation |
handleManagedRedirects and friends | @sonordev/site-kit/seo/redirects |
LandingPage, landingPageMetadata | @sonordev/site-kit/website/landing |
formatBookingTime, formatBookingDate | formatTime, formatDate from @sonordev/site-kit/sync |
The codemod rewrites these imports, including the two renamed ones, and
keeps type imports on the root. It flags, rather than rewrites, a namespace
import (import * as SK), a require, or a re-export from the root. The full
list is src/shared/module-map.json (rootRuntime).
2. The setup CLI is its own package: sonor-setup
The CLI (init, scaffold, codemods, OG cards, GEO wiring, verify) was 3 MB of
every site's install and forced a site-kit release for every setup-only fix.
It's now sonor-setup.
npx sonor-setup …keeps working unchanged: npx fetches the package.- A site whose package.json scripts run
sonor-setup(an OG step that runssonor-setup og, say) needs it as a dev dependency. The codemod adds"sonor-setup": "^7.0.0"for you. sonor-register-sitemapstays in site-kit, since sites run it from their postbuild. Nothing to change.- The
site-kitbin alias for the CLI is gone (no site used it).
3. One entry per Sonor module (old paths still work)
New homes, each the same module as before:
- Website:
./website/{popups,images,slots,cms,landing,cta-bar} - SEO:
./seo/{sitemap,robots,indexnow,redirects,og,og/route,llms,llms/client,llms/contract,meta/contract,pages/contract} - Website chat:
./chat, and popups:./website/popups(both out of./engage, which Sonor retired with the Engage module)
The old paths keep working through 7.x and are removed in 8.0. The
codemod moves them anyway, so a touched site is done in one pass: chat
imports go to ./chat, popup types to ./website/popups under their new
names (EngageElement is SitePopup). It flags EngageWidget, which draws
both and which SiteKitLayout already mounts. SiteKitLayout gains chat
and popups props; engage is an alias (engage={false} still turns both
off). Since 7.2.0, popups render only from blocks: one made in Engage Studio
isn't drawn, so make it again in Sonor (Website → Popups & Banners).
4. ESM only, Next 16 only
site-kit ships ES modules alone ("type": "module"). Next, Turbopack and the
kits don't notice. Node 20.19+/22.12+ can require() it too, so a
next.config.ts that imports @sonordev/site-kit/config keeps working. A
site-side script that require()s site-kit on an older Node would break.
The next peer is ^16. Next 16 renamed middleware.ts to proxy.ts, and
the codemod moves it: the file, a named middleware export (to proxy),
and createMiddleware from @sonordev/site-kit/middleware (to createProxy
from /proxy). The old names work through 7.x.
The proxy goes beside the app directory. Next reads it from the project
root, or from src/ when the app is src/app, and silently ignores one
anywhere else: the build passes, but the site sends no security headers and
runs no managed redirects. So on a src/app site the codemod writes
src/proxy.ts, with the file's relative imports re-pointed. Before
sonor-setup 7.1.2 it renamed the file in place, which left a root proxy.ts
on those sites; rerunning the codemod moves it, and npx sonor-setup doctor
warns about any proxy Next doesn't read.
It won't move a file that sets runtime (a proxy file can't; the build
throws), and says so: remove the export, check the logic still runs on your
host, rerun. It never moves onto a proxy Next already runs: with one in each
place, it reports both and changes neither. npx sonor-setup next16 runs
just this part.
5. Removed (nothing used them)
@sonordev/site-kit/searchand/search/contract@sonordev/site-kit/redirects/not-found(resolveManagedRedirect), and with it thex-sk-pathrequest header the proxy stamped for it and theSK_PATH_HEADERexport. Managed redirects run in the proxy.- The postinstall GEO bootstrap (
SITE_KIT_AUTO_GEO=1). Runnpx sonor-setup geoinstead. site-kit no longer runs anything at install. @sonordev/site-kit/setup(an empty stub since 2.0),LocationPageContentandgetLocationSection(they sent aproject_id),identifyTopicClusters(usegetTopicCluster),formatContentSignals, and theSiteKitConfigtype (notwithSiteKitConfig, which stays).- Source maps. The package no longer ships
.mapfiles (7.3 of 6.x's 11 MB).
Still accepted and ignored until 8.0, because sites pass them:
contentSignals on createRobotsTxtHandler, nativeReturnTo on forms, and
<ManagedScripts />.
6. Behavior worth knowing
- react-markdown is no longer installed with site-kit. The chat widget
renders markdown with
marked, already a dependency. A site that importsreact-markdownitself without listing it (it only worked because npm hoisted site-kit's copy) must add it. sonor-register-sitemapreads .env files the way Next does: a variable the host set wins over every file, then.env.production.local,.env.local,.env.production,.env. It used to let.env.localbeat the host.
Optional, and new in 7.x
- Cache Components.
cacheComponents: truein next.config works with site-kit now (it failed every page through 6.x). Remove route segment configs (dynamic,revalidate) when you turn it on; Next rejects them. - Agent tools.
npx sonor-setup mcpgives the site an MCP endpoint with the built-in Sonor tools (business profile, services, FAQ, pages, articles, reviews; inquiries, availability and offerings when you ask), the server card, and on Netlify the rate-limited relay. Sonor's AI Visibility tab then shows which agents used them. A site that already runs its own MCP server (a hand-written one) is left exactly as it is: nothing in 7.0 turns anything on for it. To have Sonor see its calls, addonToolCall: reportToolCallsToSonor()to itscreateMcpHandler. @sonordev/contractsis for the APIs and the dashboard; sites keep importing@sonordev/site-kit/*/contract, which is the same code.- Live updates (7.1).
npx sonor-setup scaffoldwrites the route Sonor calls when content changes,app/api/seo-revalidate/route.ts, andnpx sonor-setup doctorchecks for it. A site with articles getscreateRevalidateRoute({ publicationBasePath: '/insights' })with its own path, read from the app directory (a dynamic page that renders site-kit articles, or a[slug]route under a folder like/blogor/news). When more than one folder looks like the publication, it writes the one-line route and lists them.
Kits built on site-kit
agency-site-kit and re-site-kit import only entries 7 keeps unchanged
(/client, /server, /llms, /forms, /mcp, /portfolio/contract),
so their >= peer ranges already accept 7.