Skip to content

For developers

Publish an extension

Extensions are published from the CLI with a user token. The registry validates the version, refuses to overwrite history, and serves the archive to anyone entitled to it.

Terminal
# install the CLI $ npm install -g module-registry-client-lib # publish to the stable channel $ msc publish --modulePath=./dist \ --userToken=$USER_TOKEN --tag=main

What your package must contain

These fields drive everything a visitor sees on the marketplace — name, summary and category. Most of them live in package.json; the two long texts are read from files in the module root.

FieldComes fromRequiredWhat it is
appIdstringpackage.jsonRequiredUnique id in the registry and in every install command. Lowercase, no spaces — it is the primary key, so it can never be changed after the first publish.
appNamestringpackage.jsonRequiredThe human-readable name shown on the card and detail page. Falls back to appId when omitted.
versionstring (semver)package.jsonRequiredThe release being published, e.g. 1.4.2. Must be valid semver and higher than the current latest on the tag; an existing version is never overwritten.
descriptionmarkdownREADME.mdRequiredThe long description rendered on the detail page. Not read from package.json — the whole README.md in the module root is taken as-is.
changelogmarkdownCHANGELOG.mdRequiredThe release history shown on the Changelog tab. Also taken from the file in the module root, not from package.json.
categorystring (slug)package.jsonRequiredThe slug of an existing marketplace category, e.g. payment. An unknown slug is silently dropped and the extension ends up uncategorised.
appTagsstring[]package.jsonOptionalFilter chips on the catalog page. When missing, the standard keywords array is used instead.
iconstring (SVG markup)package.json / icon.svgOptionalThe card and detail icon, stored as inline SVG source rather than a URL. An icon.svg file in the module root always wins over this field.
appSupportstring (URL)package.jsonOptionalIssue tracker link shown in the Support block. When missing, the issue field is used instead.
mmDependencies{ appId: semver range }package.jsonOptionalOther registry extensions this build needs, as an id → version-range map. The resolver picks a compatible version at install time, so this is not the same as npm dependencies.

A minimal package.json

name and version are the usual npm fields — everything with an app prefix is what the marketplace reads.

{ "name": "sails-hook-my-extension", "version": "1.4.2", "appId": "my-extension", "appName": "My Extension", "category": "payment", "appTags": ["payment", "checkout"], "appSupport": "https://github.com/acme/my-extension/issues", "mmDependencies": { "another-extension": "^2.0.0" } }

README.md and CHANGELOG.md must exist in the module root. If you ship a settings directory, every JSON file needs a key and a type — and the key has to be unique across every extension on the platform.

Publishing rules

  • 1

    Versions are semantic and final

    Only valid semver is accepted, and an existing version is never rewritten.

  • 2

    Each tag only moves forward

    Within a tag you can only publish higher than the current latest. To ship something lower, publish it under a different tag.

  • 3

    main is the default channel

    Missing or invalid tags fall back to main. Use staging for pre-release builds — a staging build can later be promoted to main at the same version.

How users install your builds

The channel decides which version latest resolves to.

Stable — the default
msc install --appId=your-extension
Staging, falling back to stable
msc install --appId=your-extension --channel=staging
Highest version across every channel
msc install --appId=your-extension --channel=any
An exact version
msc install --appId=your-extension --version=1.4.2

Get a publisher token

Publishing needs a user token tied to your account. Write to us with the appId you want to claim and what the extension does.