107 lines
9.5 KiB
Markdown
107 lines
9.5 KiB
Markdown
---
|
|
title: "company-tech-blog / Why PlanetScale Chose NanoIDs for Its API"
|
|
source_type: company-tech-blog
|
|
url: https://planetscale.com/blog/why-we-chose-nanoids-for-planetscales-api
|
|
archive_url:
|
|
vendor: PlanetScale
|
|
related_branches: [feature-resource-identifier-contract]
|
|
related_projects: [ca-skeleton]
|
|
tags: [company-tech-blog, ca-skeleton, api-design, nanoid, resource-identifier, public-id-separation]
|
|
created: 2026-05-31
|
|
status: raw
|
|
confidence: medium
|
|
last_reviewed: 2026-05-31
|
|
---
|
|
|
|
# company-tech-blog / Why PlanetScale Chose NanoIDs for Its API
|
|
|
|
> Layer: `raw/company-tech-blogs/` — 외부 기업 기술 블로그 원문 발췌·출처 기록.
|
|
> PlanetScale 엔지니어링 블로그. `source_type: company-tech-blog` = **사례/관점**. 공식 best practice 또는 normative standard 로 취급 금지.
|
|
> 검증된 요약은 `/ingest` 후 `wiki/concepts/` 또는 `wiki/projects/` 에 별도 작성.
|
|
|
|
## Parent / 활용 branch (필수)
|
|
|
|
> 이 자료는 `feature-resource-identifier-contract` branch 의 구현 결정 근거로 보관됨.
|
|
|
|
| Branch | 이 자료가 정당화하는 결정 |
|
|
|---|---|
|
|
| [[raw/branch-notes/feature-resource-identifier-contract]] | D1 (resource ID default 형식) — NanoID 실세계 채택 사례: URL-safe 21자 alphanumeric, UUID 대비 가독성·더블클릭 선택성 이점 |
|
|
| [[raw/branch-notes/feature-resource-identifier-contract]] | D2 (charset / encoding) — NanoID 의 URL-safe alphabet (`0-9a-z` 또는 configurable) 실사용 근거 |
|
|
| [[raw/branch-notes/feature-resource-identifier-contract]] | D10 (DB primary key) — API-facing ID 와 DB internal PK 를 분리한 실제 구현 패턴 (Rails `public_id` column + `BigInt` PK) |
|
|
| [[raw/branch-notes/feature-resource-identifier-contract]] | D11 (Public ID vs Internal Sequence) — `public_id` (NanoID) + auto-increment `BigInt` PK 의 Dual 컬럼 패턴 사례 |
|
|
|
|
## 출처 / Source
|
|
|
|
- 원본 URL: https://planetscale.com/blog/why-we-chose-nanoids-for-planetscales-api
|
|
- 아카이브 URL: (미확인)
|
|
- 저자 / 조직: PlanetScale Engineering Blog
|
|
- 발행일: (확인 필요 — 페이지에서 날짜 추출 불가)
|
|
- 마지막 확인일: 2026-05-31
|
|
|
|
## 왜 저장했는지 / Why archived
|
|
|
|
PlanetScale 이 UUID 대신 NanoID 를 API 식별자로 채택한 이유와 구체적인 구현 방식을 설명한 기술 블로그. `feature-resource-identifier-contract` branch 의 D1 (형식 결정), D2 (charset), D10 (DB PK 정책), D11 (Public vs Internal 분리) 결정을 실제 production 사례로 뒷받침하는 증거 자료.
|
|
|
|
## 핵심 인용 / Key quotes (verbatim, 5개)
|
|
|
|
> [§ 도입부 — 동기] "we wanted to avoid using integer IDs so that we wouldn't reveal the count of records in all our tables"
|
|
|
|
> [§ UUID 문제점 — UX] "Try double clicking on that ID to select and copy it. You can't. The browser interprets it as 5 different words."
|
|
|
|
> [§ NanoID 선택 — 충돌 확률] "This gives us a 1% probability of a collision in the next ~35 years if we are generating 1,000 IDs per hour."
|
|
|
|
> [§ 구현 — Public ID vs Internal PK] "For all public-facing models, we have added a `public_id` column to our database. We still use standard auto-incrementing `BigInt`s for our primary key."
|
|
|
|
> [§ 결론 — 개발자 경험 철학] "These seemingly small details, like being able to quickly copy an ID, all add up."
|
|
|
|
## Claims Extracted / 추출된 주장
|
|
|
|
> 이 자료가 **직접 말하는 것만** claim 으로 분리한다. PlanetScale 의 engineering blog = `company-case-study` strength.
|
|
> 공식 best practice 또는 normative recommendation 으로 취급 금지 — 이 자료만으로 "NanoID 가 UUID 보다 항상 낫다" 는 증명 불가.
|
|
|
|
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|
|
|---|---|---|---|---|---|
|
|
| PLANETSCALE-NANOID-C1 | PlanetScale 은 integer ID 가 테이블 레코드 수를 노출한다는 이유로 integer ID 를 거부하고 opaque ID 를 선택했다 | "we wanted to avoid using integer IDs so that we wouldn't reveal the count of records in all our tables" | `company-case-study` | Sequential integer ID 를 외부 API 에 직접 노출하는 설계 | Integer ID 가 모든 시스템에서 보안 위협임을 증명하지는 않음; UUID 이외 대안(ULID, CUID2 등) 의 비교 우위는 미언급 |
|
|
| PLANETSCALE-NANOID-C2 | UUID 의 하이픈 구분자로 인해 브라우저 더블클릭 선택이 불가능하고, 이것이 개발자 경험(UX)에서 실질 불편이다 | "Try double clicking on that ID to select and copy it. You can't. The browser interprets it as 5 different words." | `company-case-study` | 브라우저에서 사용자가 ID 를 복사해야 하는 API / admin UI 가 있는 시스템 | UUID dashed format 이 모든 환경에서 사용 불가임을 증명하지 않음; 터미널·로그 환경에서는 더블클릭 이슈 없음 |
|
|
| PLANETSCALE-NANOID-C3 | NanoID 12자 + `0-9a-z` alphabet 기준, 시간당 1,000개 생성 시 35년 내 충돌 확률 1% — PlanetScale 이 이를 수용 가능한 수준으로 판단했다 | "This gives us a 1% probability of a collision in the next ~35 years if we are generating 1,000 IDs per hour." | `company-case-study` | 동일한 12자 / 36-char alphabet / 시간당 1,000 ID 이하 생성 조건 | 이보다 높은 생성 빈도(예: 시간당 100만 개)에서의 충돌 확률; 다른 length 또는 alphabet 에서의 안전성; NanoID 의 공식 사양은 별도 검증 필요 |
|
|
| PLANETSCALE-NANOID-C4 | PlanetScale 은 외부 공개 모델에 `public_id` 컬럼을 추가하고, DB PK 는 기존 auto-increment `BigInt` 를 유지했다 | "For all public-facing models, we have added a `public_id` column to our database. We still use standard auto-incrementing `BigInt`s for our primary key." | `company-case-study` | API-facing ID 와 DB internal PK 를 분리해야 하는 시스템 (Dual 컬럼 패턴) | `BigInt` PK + `public_id` 가 ca-skeleton 의 최적 패턴임을 증명하지 않음; External-only (PK=NanoID) 패턴의 trade-off 는 미언급 |
|
|
| PLANETSCALE-NANOID-C5 | ID 의 복사 편의성 같은 작은 UX 디테일이 누적되어 전반적인 개발자 경험에 영향을 준다는 것이 PlanetScale 의 철학이다 | "These seemingly small details, like being able to quickly copy an ID, all add up." | `company-case-study` | 외부 API 식별자 설계 시 개발자 경험(DX)을 고려 기준으로 포함하는 맥락 | 이 철학이 보편적으로 적용 가능하거나 다른 trade-off(DB 성능, 보안)보다 우선해야 함을 증명하지 않음 |
|
|
|
|
## Usage Boundaries / 적용 경계
|
|
|
|
### 이 자료가 직접 증명하는 것
|
|
|
|
- `PLANETSCALE-NANOID-C1`: Sequential integer ID 의 레코드 수 노출 위험 — PlanetScale 사례 수준
|
|
- `PLANETSCALE-NANOID-C2`: UUID dashed format 의 브라우저 더블클릭 UX 문제 — 구체적 재현 가능한 사실
|
|
- `PLANETSCALE-NANOID-C3`: NanoID 12자 / 36-char alphabet / 시간당 1,000개 생성 조건에서의 충돌 확률 수치 — PlanetScale 계산 기준
|
|
- `PLANETSCALE-NANOID-C4`: `public_id` (NanoID) + auto-increment `BigInt` PK Dual 컬럼 패턴 — PlanetScale prod 구현 사례
|
|
- `PLANETSCALE-NANOID-C5`: ID 복사 편의성이 개발자 경험에 누적 기여함 — PlanetScale 의 설계 철학
|
|
|
|
### 이 자료가 증명하지 않는 것
|
|
|
|
- NanoID 가 UUID v7 / ULID / CUID2 보다 **일반적으로** 우수한 선택임 (비교 데이터 없음)
|
|
- NanoID default 21자 길이의 충돌 확률 (본 글은 12자 기준)
|
|
- `public_id` Dual 컬럼 패턴이 external-only 패턴보다 ca-skeleton 에 적합한지 (trade-off 비교 미언급)
|
|
- NanoID 가 DB index 성능에 미치는 영향 (random insert B-tree fragmentation 등 — time-ordered ID 와 동일한 약점 언급 없음)
|
|
- PlanetScale 의 NanoID alphabet 이 URL-safe RFC 3986 `unreserved` charset 과 정확히 일치하는지
|
|
|
|
### 내 프로젝트에 적용하려면 추가 확인이 필요한 것
|
|
|
|
- ca-skeleton 의 실제 ID 생성 빈도와 12자 충돌 확률의 관계 — 더 높은 빈도라면 21자(NanoID default) 또는 26자(ULID) 검토
|
|
- NanoID 공식 사양에서 21자 / URL-safe alphabet 의 충돌 확률 공식 검증 (별도 official-doc 필요)
|
|
- Dual 컬럼(public_id + BigInt PK) vs External-only (NanoID as PK) 의 ca-skeleton 맥락 trade-off — D11 결정 전 Shopify / Stripe 사례 추가 비교 필요
|
|
|
|
## 메모 / Notes
|
|
|
|
- 본 자료의 alphabet 예시 `0123456789abcdefghijklmnopqrstuvwxyz` (36자) 은 NanoID 의 URL-safe default alphabet (64자: `A-Za-z0-9_-`) 과 다름 — PlanetScale 이 custom alphabet 을 사용했을 가능성. D2 (charset 결정) 시 NanoID 공식 문서 별도 확인 필요.
|
|
- Rails 구현에서 `before_create` callback + 충돌 시 retry 로직 언급 — Java/Spring 에서의 동등 구현 패턴은 본 자료로 추론 불가.
|
|
- Go 구현에서 `go-nanoid` 라이브러리 사용 언급 — Java 생태계 라이브러리(예: `nanoid-java`) 와는 별개 검증 필요.
|
|
- 충돌 확률 계산에 "NanoID collision tool" 사용 언급 — https://zelark.github.io/nano-id-cc/ 로 추정되나 URL 미확인.
|
|
|
|
## Related / 관련
|
|
|
|
- 같은 주제 다른 company-tech-blog (예정): `raw/company-tech-blogs/shopify-public-private-id` — Dual 컬럼 패턴 비교
|
|
- 같은 주제 다른 company-tech-blog (예정): [[raw/company-tech-blogs/segment-ksuid.md]] — KSUID 사례 (time-ordered 대안)
|
|
- 공식 문서 (예정): [[raw/official-docs/nanoid-spec.md]] — NanoID 21자 default / URL-safe alphabet / 충돌 확률 공식
|
|
- 이 자료를 인용한 branch: [[raw/branch-notes/feature-resource-identifier-contract]]
|