For background context and links to other threads, see Survey of organizational ownership and registry namespace designs for Cargo and Crates.io. This thread assumes that one has been read.
This thread is for summarizing approaches for organizational namespaces in the registry. Other general approaches include:
- Child Thread: Survey of organizational ownership designs for Cargo and Crates.io
- Child Thread: Survey of alternative identifier designs for Cargo and Crates.io
Debating which proposal Cargo and Crates.io should go with is off-topic for this thread. Please create your own thread.
Prior art
Those relevant for this thread
Note that other ecosystems continue to exist with flat namespaces, including
- RubyGems
- PyPI
- Hex
- Hackage
- CRAN
- LuaRocks
References
- blog: Package Management Namespaces (2026)
- PackagingCon: What's in a name(space)? – Adam Harvey (2023)
CPAN
Perl has partially open namespaces, meaning you can add new modules, or namespaces, under an existing one but you can't add arbitrary content to another namespace (TODO: verify these details).
These namespaces are reflected in CPAN, meaning there is a 1:1 relationship between the package's name in the registry and how you use access that package in your Perl code (TODO: is it 1:1 like packages-as-namespaces or like Python where it is by convention). Perl and CPAN allow arbitrary levels of nesting. These namespaces are public, meaning anyone can publish to them.
Culturally, the Perl community focused on coherent APIs, organizing around function, and did not abuse this for organizational namespacing.
References:
npm scopes
Packages can be named @myorg/mypackage.
The @ is to avoid referring to githuborg/repo and to disambiguate import paths.
myorg is a concept on the registry server.
Packages are private to myorg by default.
Scopes are optional. It seems that exist projects have mostly kept to their flat names while new projects have used scopes. Scopes are mostly used for organizations.
Scopes are first-come-first-serve. Scope-level account management exists to deal with ownership, transfer, dispute resolution, etc.
Compared to use cases:
- Must trust the namespace; no additional verification
- Squatting and typo squatting is reduced to the namespace portion
- Not friendly to renames or namespace transfers
Compared to requirements:
- Using
/complicates the URL story for crates.io and docs.rs - Using
@namespace/avoids complications in parsing feature activations (@disambiguates/) and PackageId Specs (@at start is unambiguous in short form,@disambiguates/in URL form`) - Access of namespace in Javascript doesn't translate to Rust code and a design there would be needed
References:
Packagist (PHP)
Packages can be named myorg/mypackage
TODO: any more details?
Maven groupId
The groupId uses a reverse domain naming.
These namespaces are verbose.
The groupId corresponds to a controlled domain using a DNS TXT record.
Governance of namespaces is delegated to ICANN.
Github users without a dedicated domain can use io.github.username.
To avoid breaking users, some organizations choose to continue to publish under a previous name.
From Package Management Namespaces | Andrew Nesbitt
In January 2024, security firm Oversecured published MavenGate, an analysis of 33,938 domains associated with Maven group IDs. They found that 6,170 of them, roughly 18%, had expired or were available for purchase.
Compared to use cases:
- Users can't trust the ownership of namespaces due to domain expirations
- Squatting and typo squatting is reduced to the namespace portion
Compared to requirements:
- Not friendly to renames or namespace transfers
- Squatting is delegated to ICANN
- Barrier for participation is higher on a technical and potentially financial level
- Access of namespace in Java doesn't translate to Rust code and a design there would be needed
References:
Nuget prefix reservation
Organizations can register package name prefixes that give them exclusive access to publishing under. These packages get a badge. Badges are permanent.
Existing packages at time of prefix registration are still allowed to exist and don't prevent registration of the prefix but they do not get the reserved prefix badge.
Only one owner of the prefix needs to be an owner of a package to get the badge. Package owners who don't own the prefix cannot remove owners that do. An owner of the prefix must always be the owner of the package to ensure the badge is permanent.
Sub-prefixes can be carved out and transferred.
An owner can mark a prefix as public, allowing anyone to publish to it.
Requesting a prefix is done by emailing nuget.org maintainers who also handle disputes. Unclear what verification is done.
Compared to use cases:
- Squatting and typo squatting is reduced to the prefix portion
- Not friendly to renames or prefix transfers
Compared to requirements:
- Could break up existing culture of publishing packages under other's prefixes
- Potential for abuse with people reserving prefixes used by other projects
- Verification process is pushed onto the crates.io team
References:
Potential solutions
Partially-open Rust namespaces (in-work)
See Survey of organizational ownership and registry namespace designs for Cargo and Crates.io for the description.
While people may choose to misuse this for organizational registry namespaces, they will have to deal with misalignments and could set a negative example for others, putting them down the wrong path.
As this is focused on APIs and not Organizations, the following are examples of features that are out of scope:
- helping users with renames
- verification of a namespace's ownership
- arbitrary depth to allow both organization and API namespacing
- preventing participation in a namespace across dependency sources
While the following are examples of potential features that would be in scope:
- Aligning the package and registry name with the Rust namespace
- Suggesting other packages from the namespace (e.g. in
cargo add) - Navigating within the namespace (e.g. on crates.io and docs.rs)
- Relaxing the orphan rules within a namespace
As the registry namespace is the Rust namespace, nesting under an organization's name would also lead to more verbose code.
Compared to use cases:
- Must trust the namespace; no additional verification
- Squatting and typo squatting is reduced to the namespace portion
- Not friendly to renames but renames are only a problem if the root package is being renamed
- Not friendly to transfers but transfers are only a problem if something is being promoted / demoted out of the official API and not based on transferring ownership
Compared to requirements:
Unreserved prefixes (no-op)
Maintainers could name their package <namespace>-<name>.
For brevity in code,
maintainers can drop the namespace within Rust by setting lib.name = "name"
or users can rename the package in their dependencies table.
Compared to use cases:
- No trust in the namespace as anyone can publish in it
- Not friendly to renames or namespace transfers
Compared to requirements:
- If using the
lib.nametrick, how to reference the package in Rust code is unclear though that is an existing issue for renames and kebab case (cargo#15887) - Without the
lib.nametrick, access within Rust is verbose
Future possibilities:
- Encode this in the ecosystem by adding to
.cargo/config.tomlacargo-new.prefix = <string|bool>with a default of$USERfor packages not being added to workspaces- advice will be given for changing this
- Users can always disable with
cargo-new.prefix = false - Repos that want to default to their Rust namespace can set
cargo-new.prefix = "namespace::"
- Resolve cargo#15887, making discovery of Rust namespace more discoverable
Organizational registry namespaces
There are many variants of this that have come and gone where most of the parts can mixed and matched.
[lib] and [[bin]] crates that infer their name from package.name would not include the namespace.
Alternatively, the user could be forced to rename the package but that is more of an advanced feature that we shouldn't force on all users.
Import collisions are possible which impacts usability.
Like with multiple semver-major versions,
users can rename the package to avoid collisions.
Specifying a namespace:
- A separate package field (e.g.
package.organization)- Still needs a separator syntax for dependencies and
cargo addunless you also add the field/flag to them which makes things more verbose and makes it easy to accidentally leave off in the dependency and get something from the flat namespace - Having separate fields makes it less likely people will be confused about how to reference the package in Rust since it can just be dropped
- Still needs a separator syntax for dependencies and
@namespace/name- Looks like
namespaceshould be used in Rust but generally it is dropped instead - Works within Cargo but complicates docs.rs and crates.io URL schemes
- Common prefixes for CLI completions, at least, adds friction to using completions
- Looks like
name@namespace- Like with numeric suffixes, seems easier to train users to drop the suffix in Rust code than a prefix though resolving cargo#15887 can help
- Starts with a more unique name, making CLI completions easier
- If namespaces are relevant to sort order, then this runs counter to that but in that case, would partially open Rust namespaces be more appropriate?
- However, causes ambiguous short-form PackageID Specs
name#namespace- Similar to
name@namespacebut avoids the PackageID Spec issue - For PackageID Spec URL form, would be percent encoded
- Framing this as an organizational tag can help in training users to drop the suffix when using name in Rust code though resolving cargo#15887 can help
- Similar to
Namespace reservation:
- None, reserved on first-publish
- None, explicit, high friction reservation workflow
- No official API, against the terms of service to automate
- Extreme defaults for rate limiting (e.g. 1 a day) and maximum namespaces per account (e.g. 3)
- Github Org
- Org names are mutable which means you can lose access to your package and other people could publish to it
- We want to decouple crates.io from github
- Git hosting is an implementation detail and users should feel free to migrate hosts without breaking users
- Reverse fqdn
- Barrier for participation is higher on a technical and potentially financial level
- Ownership is mutable which means you can lose access to your package and other people could publish to it
Helping with renames and transfers:
- Add Index redirect which get resolved as the entry they point to
- Moving the everything under the old name to the new name and redirecting the old name to the new name would likely be simplest
- Assumes no version conflicts between the two names
- TODO: can this work with the resolver?
- Or you can register redirects with the server so that when you publish to a package, redirect entries get added to the old name
- Care might be needed if we want to allow old versions under the old name to work with Cargo <1.19 as older versions of Cargo don't ignore unknown entries (#4026)
- TODO: can this work with the resolver?
- The redirect may have a minimum MSRV for access
- Likely need safe guards that entries that used to exist have a higher MSRV (and maybe publish date) than when redirect support was added
- Or you redirect the new name to the old name but then we can't treat one name as canonical
- Could potentially help with normalizing
_/-in package names on the registry side (only the most obvious: all one or all the other and not every combination of mixed) - Registry should enforce redirect cycle checks
- Should registries resolve multiple redirects into one redirect?
- Moving the everything under the old name to the new name and redirecting the old name to the new name would likely be simplest
- Add mutable metadata to the registry and include a way to direct users to the new name of a package
- Works without perfect version continuity
- Would also help with deprecations (see also This Development-cycle in Rust)
- Have the resolver unify package names across namespaces
- If maintainers decide to generically name their packages (e.g.
foo/derive) instead of using partially-open Rust Namespaces, then this will lead to bad results - Likely wouldn't work with the resolver as the resolver needs to be able to enumerate all versions for a package at once and not as we discover each workspace used
- Could also have problems with ambiguous versions
- If maintainers decide to generically name their packages (e.g.
Publish permissions would only be managed at the namespace level. Any publish permission changes at the package level will return errors. Motivation:
- It supports the emphasis that this is organizational related. All of the packages should be coming from the same entity anyways.
- This operates as an MVP, giving us an opportunity to gauge the need for finer grained controls and collect use cases to see if we can come up with ways that keep the emphasis on organizations while giving them the flexibility they need
- Feedback we've heard so far, organizations only want a single publisher for their packages.
References:
- Internals: Pre-RFC Domains as namespaces (2018)
- Internals: Pre-RFC: Author Attached Crates-io Names (2020)
- RFC 3384: uri crates (2023) (rendered)
- Internals: Pre-RFC: User namespaces on crates.io (2020)
- RFC 2978: Proposal for user namespaces on crates.io (2020) (rendered)
- Zulip: crate namespacing (2023)