Rust 라이브러리를 crates.io에 배포하는 방법

Rust로 라이브러리를 만들었으면 crates.io에 배포해서 다른 사람들이 cargo add로 쓸 수 있게 해야겠죠. 처음 해 보면 뭘 준비해야 하는지 헷갈려서, 순서대로 정리해 볼게요.

1. crates.io 계정 준비

crates.io에 GitHub 계정으로 로그인해요. 그다음 Account Settings → API Tokens에서 토큰을 만들어요.

터미널에서 로그인해요. cargo login을 실행하면 토큰을 입력받아요. 토큰을 명령줄 인자로 넘기면 셸 기록에 남으니, 프롬프트에 붙여 넣는 게 안전해요.

Bash
cargo login
# 프롬프트에 토큰 붙여 넣기

한 번만 하면 돼요. 토큰은 ~/.cargo/credentials.toml에 저장돼요.

2. Cargo.toml 필수 필드

crates.io에 publish하려면 Cargo.toml에 최소한 이 필드들이 있어야 해요.

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에는 이렇게 적어요.

TOML
license = "MIT OR Apache-2.0"

단일 라이선스를 쓰고 싶다면 이렇게 적어요.

TOML
license = "MIT"
# 또는
license = "Apache-2.0"

4. README.md

crates.io 페이지에 표시돼요. 최소한 이 내용은 넣어 두세요.

Markdown
# 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으로 확인해요.

Bash
cargo publish --dry-run

이 명령이 하는 일이에요.

  1. 패키지 압축 (어떤 파일이 포함되는지 확인)
  2. 압축된 패키지로 빌드 테스트
  3. 실제 업로드는 하지 않음

문제가 있으면 여기서 에러가 나요.

자주 나는 에러들

정확한 메시지는 Cargo 버전마다 조금씩 달라요. 아래는 내용을 요약한 거예요.

TEXT
description 누락
→ Cargo.toml에 description 추가

license 누락
→ Cargo.toml에 license 추가

패키지 크기 초과 (crates.io 업로드 한도)
→ .gitignore나 Cargo.toml의 [package] exclude로 불필요한 파일 제외

6. 실제 배포

Bash
cargo publish

성공하면 이런 메시지가 나와요.

TEXT
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가 있는 워크스페이스에서는 의존성 순서대로 배포해야 해요.

TEXT
my-core    → 의존성 없음 (1번)
my-render  → core에 의존 (2번)
my-lib     → core + render에 의존 (3번)
my-cli     → 전부 의존 (4번)

path + version 병기

로컬에서는 path로 참조하지만, crates.io에서는 version이 필요해요. 둘 다 적으면 돼요.

TOML
# Before (로컬 전용)
my-core = { path = "../my-core" }

# After (배포 가능)
my-core = { version = "0.1.0", path = "../my-core" }

이렇게 하면 이렇게 동작해요.

  • 로컬 빌드: path를 사용
  • crates.io에서 다운받은 사용자: version으로 resolve

배포 순서 실행

Bash
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 에러를 돌려줘요.

TEXT
error: Too Many Requests
Please try again after [시간]

이 에러가 나면 메시지에 적힌 시간이 지난 뒤 다시 시도하면 돼요.

8. 버전 업데이트

코드를 고친 뒤 새 버전을 배포하는 순서예요.

  1. Cargo.toml의 version을 올려요
  2. 의존하는 다른 crate에서도 version을 맞춰요
  3. cargo publish
TOML
# 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 등)를 넣지 마세요. 한 번 올리면 되돌릴 수 없어요.
Bash
# 특정 버전 yank (신규 설치 차단)
cargo yank --version 0.1.0

# yank 해제
cargo yank --version 0.1.0 --undo

10. .gitignore / 패키지 제외

publish할 때 불필요한 파일이 들어가지 않게 제외할 수 있어요.

TOML
# Cargo.toml
[package]
exclude = ["tests/fixtures/*", "benches/*", ".github/*"]

반대로 포함할 파일만 지정할 수도 있어요.

TOML
[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이 병기되어 있는지 (워크스페이스)