Create new Site
Each site in the CMS5 multisite is a Strapi plugin under src/plugins/. This guide walks through scaffolding a new site plugin, registering it, wiring up the shared slug logic, and building it.
For this example we create a site called andronis.
1. Scaffold the plugin
Open a terminal in the cms5-backend root and run the command below. The argument is the path where the plugin is created, so pass the full src/plugins/<NAME> path (passing just <NAME> would create the plugin in the repo root instead):
npx @strapi/sdk-plugin@latest init src/plugins/<NAME>Important: answer no to
register with the admin panel?and yes toregister with the server?. Answering no to the admin panel keeps the plugin server-only (noadmin/folder is generated).
You will be prompted for the following, in order (the plugin id must match /^[a-z0-9][a-z0-9-_]*$/):
? plugin name › andronis
? plugin id (used by Strapi) › andronis
? plugin display name › Andronis
? plugin description › Andronis CMS5
? plugin author name › John Paraskevopoulos
? plugin author email › jparaskevopoulos@nelios.com
? git url ›
? plugin license › MIT
? register with the admin panel? › no
? register with the server? › yes
? Add .editorconfig? › yes
? Use ESLint? › yes
? Use Prettier? › yes
? Use TypeScript? › yes2. Fix the plugin’s dependencies
Once the script finishes it will attempt to install node modules — it might crash, ignore it. Open the package.json of your new plugin (src/plugins/andronis/package.json) and replace the dependencies, devDependencies, and peerDependencies with the ones any other site uses:
{
"dependencies":{
"@strapi/types":"5.48.0"
},
"devDependencies":{
"@strapi/sdk-plugin":"^5.3.2",
"@strapi/typescript-utils":"^5.12.6",
"prettier":"^3.5.3",
"typescript":"^5.8.3"
},
"peerDependencies":{
"@strapi/sdk-plugin":"^5.3.2",
"@strapi/strapi":"^5.35.0"
}
}Note: These versions drift over time — always copy from the
package.jsonof an existing site plugin (e.g.src/plugins/andronis) rather than trusting the snippet above.
3. Register the plugin
Add the plugin to config/plugins.ts:
export default {
// …other plugins
'andronis': {
enabled: true,
resolve: './src/plugins/andronis'
},
// …other plugins
}Note: The key name (
andronis) must match the plugin name you used when scaffolding.
4. Generate the lifecycle hooks
Run the helper script and enter the same name you used above:
pnpm run add:pluginEnter plugin name (e.g., my-plugin): andronis
✅ register.ts has been overwritten in order to enable lifecycle hooks: src/plugins/andronis/server/src/register.ts
✅ Copied lib folder from 'demo' to src/plugins/andronis/lib
ℹ️ 'andronis' lives under src/plugins/* and will be built automatically by 'pnpm run buildAll'.This does everything needed to wire up the site’s slug logic:
- Overwrites the plugin’s
server/src/register.tswithbeforeCreate/beforeUpdatelifecycle hooks that auto-generate theSlugfield for any content type that has one, importing the shared helper from../../lib/NeliosSlug. - Copies the shared
libfolder (NeliosSlug.ts+helpers.ts) from an existing plugin intosrc/plugins/<name>/lib/, so that import resolves when the plugin is built in isolation.
Notes
- The plugin name is validated — only letters, numbers, dashes, and underscores are allowed; anything else is rejected.
- No
build:pluginsedit is needed. Becausesrc/plugins/*is a pnpm workspace, the new plugin is picked up automatically bybuild:plugins(pnpm -r --if-present build). - If the plugin already has a
libfolder it is left untouched; if no donor plugin is found, the script warns you to copy alibfolder in manually.
5. Build
To apply changes, from the plugin directory src/plugins/<name>/ run:
pnpm run buildor, during development:
pnpm run watchTo build everything (shared packages, types, all plugins, then Strapi) run from the cms5-backend root:
pnpm run buildAllReview the changes locally before deploying.