Rust 라이브러리를 crates.io에 배포하는 방법
Rust로 라이브러리를 만들었으면 crates.io에 배포해서 다른 사람들이 cargo add로 쓸 수 있게 해야겠죠. 처음 해 보면 뭘 준비해야 하는지 헷갈려서, 순서대로 정리해 볼게요.
1. crates.io 계정 준비
crates.io에 GitHub 계정으로 로그인해요. 그다음 Account Settings → API Tokens에서 토큰을 만들어요.
터미널에서 로그인해요. cargo login을 실행하면 토큰을 입력받아요. 토큰을 명령줄 인자로 넘기면 셸 기록에 남으니, 프롬프트에 붙여 넣는 게 안전해요.
cargo login
# 프롬프트에 토큰 붙여 넣기
한 번만 하면 돼요. 토큰은 ~/.cargo/credentials.toml에 저장돼요.
2. Cargo.toml 필수 필드
crates.io에 publish하려면 Cargo.toml에 최소한 이 필드들이 있어야 해요.
[package]
name = "my-awesome-lib"
version = "0.1.0"
edition = "2024"
description = "한 줄 설명 (없으면 거부됨)"
license = "MIT OR Apache-2.0"
repository = "https://github.com/username/my-awesome-lib"
| 필드 | 필수 여부 | 설명 |
|---|---|---|
name | 필수 | crate 이름 (crates.io에서 유일해야 함) |
version | 필수 | SemVer 형식 |
edition | 권장 | Rust 에디션 (2021, 2024 등) |
description | 필수 | 없으면 publish 거부됨 |
license | 필수 | SPDX 식별자 (MIT, Apache-2.0, MIT OR Apache-2.0) |
repository | 권장 | GitHub URL |
readme | 선택 | README 파일 경로 (기본: README.md) |
keywords | 선택 | 최대 5개, 검색에 도움 |
categories | 선택 | crates.io 카테고리 |
3. 라이선스 파일
Rust 생태계에서는 MIT + Apache 2.0 듀얼 라이선스를 많이 써요. 프로젝트 루트에 두 파일을 만들어요.
LICENSE-MIT— MIT 라이선스 전문LICENSE-APACHE— Apache 2.0 라이선스 전문
Cargo.toml에는 이렇게 적어요.
license = "MIT OR Apache-2.0"
단일 라이선스를 쓰고 싶다면 이렇게 적어요.
license = "MIT"
# 또는
license = "Apache-2.0"
4. README.md
crates.io 페이지에 표시돼요. 최소한 이 내용은 넣어 두세요.
# my-awesome-lib
한 줄 설명.
## 설치
\```toml
[dependencies]
my-awesome-lib = "0.1"
\```
## 사용법
\```rust
use my_awesome_lib::something;
fn main() {
// 예제 코드
}
\```
## 라이선스
MIT OR Apache-2.0
5. 배포 전 검증
실제로 publish하기 전에 dry-run으로 확인해요.
cargo publish --dry-run
이 명령이 하는 일이에요.
- 패키지 압축 (어떤 파일이 포함되는지 확인)
- 압축된 패키지로 빌드 테스트
- 실제 업로드는 하지 않음
문제가 있으면 여기서 에러가 나요.
자주 나는 에러들
정확한 메시지는 Cargo 버전마다 조금씩 달라요. 아래는 내용을 요약한 거예요.
description 누락
→ Cargo.toml에 description 추가
license 누락
→ Cargo.toml에 license 추가
패키지 크기 초과 (crates.io 업로드 한도)
→ .gitignore나 Cargo.toml의 [package] exclude로 불필요한 파일 제외
6. 실제 배포
cargo publish
성공하면 이런 메시지가 나와요.
Uploading my-awesome-lib v0.1.0
Uploaded my-awesome-lib v0.1.0 to registry `crates-io`
Published my-awesome-lib v0.1.0 at registry `crates-io`
이제 누구나 cargo add my-awesome-lib로 설치할 수 있어요.
7. 워크스페이스에서 여러 crate 배포
여러 crate가 있는 워크스페이스에서는 의존성 순서대로 배포해야 해요.
my-core → 의존성 없음 (1번)
my-render → core에 의존 (2번)
my-lib → core + render에 의존 (3번)
my-cli → 전부 의존 (4번)
path + version 병기
로컬에서는 path로 참조하지만, crates.io에서는 version이 필요해요. 둘 다 적으면 돼요.
# Before (로컬 전용)
my-core = { path = "../my-core" }
# After (배포 가능)
my-core = { version = "0.1.0", path = "../my-core" }
이렇게 하면 이렇게 동작해요.
- 로컬 빌드:
path를 사용 - crates.io에서 다운받은 사용자:
version으로 resolve
배포 순서 실행
cargo publish -p my-core
cargo publish -p my-render
cargo publish -p my-lib
cargo publish -p my-cli
-p 플래그로 특정 crate만 지정해요. cargo publish는 올린 패키지가 인덱스에 나타날 때까지 기다렸다가 끝나기 때문에, 단계 사이에 따로 기다릴 필요는 없어요. -p를 여러 번 주거나 --workspace를 쓰면 여러 crate를 한 명령으로 올릴 수도 있어요. 자세한 건 cargo publish 문서에 있어요.
Rate Limit 주의
crates.io는 짧은 시간에 너무 많이 publish하면 429 에러를 돌려줘요.
error: Too Many Requests
Please try again after [시간]
이 에러가 나면 메시지에 적힌 시간이 지난 뒤 다시 시도하면 돼요.
8. 버전 업데이트
코드를 고친 뒤 새 버전을 배포하는 순서예요.
Cargo.toml의version을 올려요- 의존하는 다른 crate에서도 version을 맞춰요
cargo publish
# 0.x 버전에서
# 호환되는 변경 (버그 수정, 기능 추가): 0.1.0 → 0.1.1
# 호환이 깨지는 변경: 0.1.0 → 0.2.0
version = "0.1.1"
Cargo의 호환성 규칙은 이래요. Cargo 문서에 따르면, 맨 왼쪽의 0이 아닌 자리가 같으면 호환되는 버전으로 봐요.
- 1.0 이상: patch(1.2.3 → 1.2.4)는 버그 수정, minor(1.2.0 → 1.3.0)는 호환되는 기능 추가, major(1.x → 2.0)는 호환이 깨지는 변경이에요.
- 0.x: 0.1.0 → 0.1.1은 호환되는 변경이고, 0.1.0 → 0.2.0은 호환이 깨지는 변경이에요. 1.0 이전에는 minor 자리가 major 역할을 해요.
9. 주의사항
- 한 번 publish한 버전은 덮어쓰거나 지울 수 없어요. yank만 할 수 있어요. yank하면 새로 의존성을 거는 건 막히고, 이미
Cargo.lock에 있는 사용자는 계속 쓸 수 있어요. - crate 이름은 먼저 등록한 사람이 가져요.
- 민감한 정보(API 키, .env 등)를 넣지 마세요. 한 번 올리면 되돌릴 수 없어요.
# 특정 버전 yank (신규 설치 차단)
cargo yank --version 0.1.0
# yank 해제
cargo yank --version 0.1.0 --undo
10. .gitignore / 패키지 제외
publish할 때 불필요한 파일이 들어가지 않게 제외할 수 있어요.
# Cargo.toml
[package]
exclude = ["tests/fixtures/*", "benches/*", ".github/*"]
반대로 포함할 파일만 지정할 수도 있어요.
[package]
include = ["src/**/*", "Cargo.toml", "LICENSE-*", "README.md"]
체크리스트
배포 전에 마지막으로 확인할 것들이에요.
-
Cargo.toml에 name, version, description, license, repository 있는지 - LICENSE 파일 존재하는지
- README.md 있는지
-
cargo publish --dry-run통과하는지 - 민감한 정보가 포함되지 않았는지
- 의존하는 crate가 이미 crates.io에 올라가 있는지 (워크스페이스)
- path 의존성에 version이 병기되어 있는지 (워크스페이스)