Guides
Publishing
Last updated October 23, 2026
The mechanics of the embr publish command have their
own page; this one is about the registry's rules.
Scopes#
First publish claims the scope for your GitHub account. From then on the scope belongs to that account — names within it are yours to manage.
Versions are immutable#
Republishing an existing version is a 409. There is no unpublish from the CLI — delisting is registry moderation, and existing lockfiles keep working even for delisted packages. Ship a new version to fix a mistake.
Two marks can change after publish: a yank and a deprecation. Neither changes the files of a version.
Several targets#
A package can ship one release for each target, with one [[target]]
table for each. A target ID is the environment for Luau, else the
environment and the language, such as roblox-alloy. Each target of a
version has its own archive and its own index entry. See
several targets.
embr publish # every target
embr publish --target roblox-alloy # one target only
Yank a version#
A yank keeps a version out of new installs. Use it for a release that is broken or unsafe.
embr yank acme/rocket@1.2.0
embr yank acme/rocket@1.2.0 --target lune # one target only
embr yank acme/rocket@1.2.0 --undo # restore it
- Fresh resolution skips a yanked version. "Latest" on the website skips it too.
- A project whose
ember.lockpins the version still installs it, with a warning. This is the cargo rule, and it keeps existing projects working. - The archive stays downloadable, for the same reason.
- Without
--target, the yank covers every target of the version. - The older
--environment <name>still works. It means the Luau target of that environment. - When every version of a package is yanked, search no longer lists it.
A yank is not a takedown. Anyone with the version in a lockfile still gets it. For malware or a leaked secret, also send a report with the Report button on the package page.
Deprecate a package or a version#
A deprecation tells users to move off a package, or off one version. The reason says why and what to use instead.
embr deprecate acme/rocket "Use acme/rocket2 instead."
embr deprecate acme/rocket@1.2.0 "Breaks on Lune 0.9; use 1.2.1."
embr deprecate acme/rocket@1.2.0 "Lune only." --target lune
embr deprecate acme/rocket --undo
- A deprecated package or version still resolves and installs. Each install that picks it prints the reason as a warning.
- The reason is 1 to 300 characters. A new reason replaces the old one.
--target <id>narrows a version's deprecation to one target. It needs thescope/name@versionform.- The website shows the reason in a banner on the package page and marks the package in search.
Only the scope's owners can yank or deprecate. Both commands sign in the
way embr publish does, and they share its rate limit of 10 calls per 10
minutes.
Logos#
[package] logo names a picture of the package: a .png, .jpg, or
.webp file inside it, at most 512 KiB. The registry shows it in place of
the box icon. See [package].
A logo must follow the policies like any other content. Anyone can report a package for an inappropriate logo with the Report button on its page.
Models#
A Roblox package can ship .rbxm models next to its code. The registry
checks each model when you publish: no scripts, one root, binary only, and
real code beside it. See Models in packages.
Authors grant co-ownership#
Every login in [package] authors is appended to the scope's owner
list on publish and can then publish to the entire scope, not just that
package. The list is append-only — removal is a manual moderation edit.
Usernames are shape-checked but not verified to exist, so a typo
silently grants a nonexistent account. Treat the authors field like an
access control list, because it is one. This scope-wide grant is subject
to change in a future release.
Authentication#
embr publish signs in with the GitHub device flow, requesting no OAuth
scopes — the registry only maps the token to a GitHub login. The token is
stored in ~/.ember/credentials.toml (0600 on unix).
embr auth logs in ahead of time, stores a token you
already have, shows the login, and logs out.
Provenance#
The repository field in a manifest is self-declared: a version can point
at any repository it likes. Provenance is what turns that link into a fact.
When a version is published from GitHub Actions with id-token: write, the
registry verifies the workflow's OIDC token and stores where the version was
really built — repository, commit, workflow, and run — and the package page
presents it in a provenance panel. Setup is a single permission line; see
embr publish.
Hand-published versions carry no provenance and are not marked as suspicious. Absence means no claim was made, not that a claim failed.
Practical rules#
- Tarballs are capped at 10 MB.
private = truemakes publish refuse the package.- Check what you ship with
embr publish --dry-run(full file list); the manifest'sincludes/excludesshape the selection. - The registry's policies cover names, takedowns, and what being public means.