Skip to content
202 linesCodeBlameRaw
1---
2title: Cargo
3description: Publish and add a workspace's Rust crates with Cargo, from a sparse registry of its own on g1t.sh, from your machine and from workflows.
4---
5
6Every workspace has a Cargo registry of its own: a sparse index, with the
7web API that `cargo publish`, `cargo yank` and `cargo search` use. It
8works with Cargo 1.74 or later, private crates included.
9
10```text
11sparse+https://g1t.sh/-/cargo/<workspace>/index/
12```
13
14Crates from crates.io still come from crates.io; only the crates you name
15with the workspace's registry come from g1t.
16
17## Set up `.cargo/config.toml`
18
19Name the registry in the project's `.cargo/config.toml`, or in
20`~/.cargo/config.toml` for every project. The name you give it is the one
21you pass to `--registry`; these pages use the workspace's slug:
22
23```toml
24[registries.acme]
25index = "sparse+https://g1t.sh/-/cargo/acme/index/"
26credential-provider = "cargo:token"
27```
28
29Cargo sends a token to a registry that asks for one only through a
30credential provider named for it. `cargo:token` keeps the token in
31`~/.cargo/credentials.toml`, which stays out of the project. To keep it in
32your system's keychain instead, name `cargo:wincred` (Windows),
33`cargo:macos-keychain` (macOS) or `cargo:libsecret` (Linux).
34
35Then give Cargo an [access token](https://g1t.sh/settings/tokens):
36
37```sh
38cargo login --registry acme
39```
40
41Cargo asks for the token and hands it to the provider. A token with full
42access works; one with scopes needs `packages:read` to add private crates
43and `packages:write` to publish and yank them.
44
45The token can also come from the environment instead of `cargo login`,
46as `CARGO_REGISTRIES_ACME_TOKEN` for a registry named `acme` (the name in
47capitals, with `-` written `_`). The `cargo:token` provider reads it from
48there, which is how [workflows](#in-workflows) give it.
49
50## Publish
51
52Say in `Cargo.toml` where the crate is published and which repository it
53comes from:
54
55```toml
56[package]
57name = "http-client"
58version = "0.3.1"
59edition = "2021"
60description = "Our HTTP client"
61license = "MIT"
62readme = "README.md"
63repository = "https://g1t.sh/acme/http-client"
64publish = ["acme"]
65```
66
67```sh
68cargo publish --registry acme
69```
70
71The first publish makes the crate. When its `repository` is a g1t.sh
72repository of the same workspace, or a repository is named like the crate
73(a crate `http_client` is also matched to a repository `http-client`), it
74is linked to that repository and has its visibility and roles: publishing needs Write on it.
75Otherwise it is the workspace's, private, and needs the workspace's Write
76base permission. See
77[who can see and publish a package](/guides/packages/#who-can-see-and-publish-a-package).
78
79`publish = ["acme"]` keeps the crate from being published to crates.io by
80mistake, and lets `cargo publish` leave out `--registry` when it is the
81only registry named.
82
83A crate may depend on crates.io crates and on other crates of the
84workspace's registry. The crate's page on g1t.sh shows the README and
85description of its highest stable version.
86
87## Add a crate
88
89```sh
90cargo add http-client --registry acme
91```
92
93That writes the dependency with its registry into `Cargo.toml`:
94
95```toml
96[dependencies]
97http-client = { version = "0.3.1", registry = "acme" }
98```
99
100`Cargo.lock` records each crate's registry and the SHA-256 of its
101`.crate` file, which g1t computes when the version is published.
102
103`cargo search --registry acme http` lists the workspace's crates you can
104see whose names match.
105
106## Names and versions
107
108A crate's name follows the crates.io rules: ASCII letters, digits, `-` and
109`_`, starting with a letter, at most 64 characters. In a workspace, names
110that differ only in case or in `-` against `_` are one name: once
111`http-client` is published, `HTTP_Client` is refused.
112
113A version is published once. Publishing a version that is already there is
114refused, as is one that differs from it only in build metadata (`1.0.0+a`
115and `1.0.0+b`), so bump `version` first.
116
117## Yank
118
119```sh
120cargo yank --registry acme http-client@0.3.1
121cargo yank --registry acme http-client@0.3.1 --undo
122```
123
124A yanked version stays in the registry: projects whose `Cargo.lock`
125names it still build, but Cargo no longer picks it for new lockfiles or
126`cargo update`. Yanking needs what publishing does. The crate's page marks
127yanked versions, and someone with Admin on the linked repository (an
128owner, for the workspace's own crates) can delete a version there for
129good.
130
131Crate owners are not kept: who may publish a crate is decided by its
132repository's roles, or the workspace's, so `cargo owner` answers with an
133error that says so.
134
135## Private and public crates
136
137A crate linked to a repository has the repository's visibility; one of
138the workspace's own is private until an owner makes it public on its page.
139
140| The workspace's crates | Without a token | With a token |
141| --- | --- | --- |
142| All public | Cargo reads the index and downloads them. | The same; the token is sent to publish and yank. |
143| Some private | The registry answers `401`: Cargo needs a token for every crate in it, public ones too. | Cargo sends the token with every request, and sees the crates the token's owner may see. |
144
145Cargo first asks for the registry's `config.json` without a token. When
146the registry answers `401`, Cargo asks again with its token, and the
147answer says `"auth-required": true`, so Cargo sends the token from then on.
148A private crate you cannot see looks exactly like one that does not exist.
149
150## In workflows
151
152A workflow's `G1T_TOKEN`, [the job's own token](/guides/actions/#the-jobs-token), can install the workspace's crates,
153and publish them with `packages: write` in its [`permissions:`](/guides/actions/#the-jobs-token). A workflow runs no `cargo login`:
154give Cargo the registry, its credential provider and the token in the
155environment, each named for the registry:
156
157```yaml
158jobs:
159 publish:
160 runs-on: ubuntu-latest
161 permissions:
162 contents: read
163 packages: write
164 env:
165 CARGO_REGISTRIES_ACME_INDEX: sparse+https://g1t.sh/-/cargo/acme/index/
166 CARGO_REGISTRIES_ACME_CREDENTIAL_PROVIDER: cargo:token
167 CARGO_REGISTRIES_ACME_TOKEN: ${{ secrets.G1T_TOKEN }}
168 steps:
169 - uses: actions/checkout@v4
170 - run: cargo test
171 - run: cargo publish --registry acme
172```
173
174| Variable | Is | Needed |
175| --- | --- | --- |
176| `CARGO_REGISTRIES_ACME_INDEX` | The registry's index, as `index` in `.cargo/config.toml`. | When no `.cargo/config.toml` names the registry. |
177| `CARGO_REGISTRIES_ACME_CREDENTIAL_PROVIDER` | `cargo:token`, as `credential-provider` in `.cargo/config.toml`. | When no `.cargo/config.toml` names the provider. Without one, Cargo refuses a registry with private crates, even with the token in the environment. |
178| `CARGO_REGISTRIES_ACME_TOKEN` | The token, for `cargo:token` to hand to the registry. | Always: `cargo publish` sends it, and Cargo sends it to read a registry with private crates. |
179
180With the project's `.cargo/config.toml` from [above](#set-up-cargoconfigtoml)
181checked in, `CARGO_REGISTRIES_ACME_TOKEN` is all a workflow sets. The same
182variables let `cargo build` and `cargo test` download the workspace's
183private crates.
184
185## Size
186
187A publish is one request with the `.crate` file inside it, and may hold at
188most 100 MB. Without the [g1t plan](/guides/usage-and-billing/#the-g1t-plan),
189a workspace's private packages may hold 500 MB and its public ones 10 GB,
190as for [container images](/guides/containers/#storage-and-pull-limits).
191A `.crate` file is stored once, by its content.
192
193## Errors
194
195| Error | Means |
196| --- | --- |
197| `401` | No token, or a wrong or expired one. Run `cargo login --registry acme` with a g1t access token, or set `CARGO_REGISTRIES_ACME_TOKEN`. |
198| `authenticated registries require a credential-provider to be configured` | The workspace has private crates, and Cargo has no provider for its token. Add `credential-provider = "cargo:token"` to the registry in `.cargo/config.toml`, or set `CARGO_REGISTRIES_ACME_CREDENTIAL_PROVIDER=cargo:token`. |
199| `403` | Signed in, but your role or your token's scopes do not allow it, or the workspace is out of free package storage. The message says which. |
200| `404` | No such crate or version, or a private one you cannot see. |
201| `400` | The publish was refused: a name that is not valid or is taken, a version already published, or metadata Cargo did not send in full. The message says which. |
202| `413` | The publish is over 100 MB. Leave large files out with `exclude` or `include` in `Cargo.toml`, and check with `cargo package --list`. |