본문으로 건너뛰기

4.1 Neon CLI와 API

Neon의 branch는 Console, CLI, REST API 세 경로에서 같은 control plane을 통해 조작합니다. 사람이 직접 확인할 때는 Console이 편하지만, CI와 스크립트에서 사용하려면 CLI나 API가 필요합니다. 이 장에서는 CLI 명령을 먼저 정리하고, CLI가 내부적으로 호출하는 API 본문과 대응해 봅니다.

설치와 인증

npm i -g neon
neon --version
neon auth

neon auth는 브라우저를 열어 OAuth 인증을 진행한 뒤 자격 증명을 로컬에 저장합니다. CI처럼 브라우저가 없는 환경에서는 API key를 환경 변수로 전달합니다.

export NEON_API_KEY=<api key>
neon projects list --api-key "$NEON_API_KEY"

API key는 Console의 Account settings에서 발급합니다. 개인 key, 조직 key, 프로젝트 범위 key가 구분됩니다. CI에는 필요한 프로젝트에만 접근할 수 있는 key를 사용하는 편이 안전합니다. neon api-keys list, neon api-keys create, neon api-keys revoke로 CLI에서도 관리합니다.

프로젝트와 branch 조회

neon projects list
neon branches list --project-id <project id>
neon branches get main --project-id <project id>

--project-id는 프로젝트가 여러 개일 때 필요합니다. 하나뿐이면 CLI가 자동으로 선택합니다. 출력 형식은 기본적으로 표입니다. --output json을 추가하면 스크립트에서 파싱하기 쉬운 JSON이 출력됩니다.

neon branches list --project-id <project id> --output json | jq -r '.[] | [.id, .name, .parent_id // "-", .created_at] | @tsv'

branch 생성

neon branches create --name feature/orders-index --parent main

부모를 생략하면 프로젝트의 default branch에서 분기합니다. 기본적으로 read-write compute가 하나 생성됩니다. 자주 사용하는 옵션은 다음과 같습니다.

옵션
--namebranch 이름. 프로젝트 안에서 유일해야 하고 최대 256자
--parent부모 branch 이름 또는 ID. 생략 시 default branch
--compute / --no-computecompute endpoint 생성 여부. 기본은 생성
--type read_write / read_onlycompute 종류. read_only는 read replica
--cu <size> 또는 <min>-<max>compute 크기. 범위를 주면 autoscaling
--schema-only데이터 없이 schema만 가진 root branch 생성
--expires-at <RFC3339>자동 삭제 시각
--protected보호 branch로 생성

--cu 0.25-2처럼 범위를 지정하면 부하에 따라 0.25 CU와 2 CU 사이에서 자동으로 조정합니다. 범위의 상한은 플랜의 autoscaling 최대치까지입니다. Launch와 Scale은 모두 16 CU입니다. 리허설이나 CI용 branch를 부모와 같은 크기로 만들지 않으면 실행 시간 비교가 왜곡됩니다. 이 점은 4.3 Schema Migration 리허설에서 다시 다룹니다.

branch 관리 명령

neon branches rename feature/orders-index feature/orders-index-v2
neon branches set-default feature/orders-index-v2
neon branches add-compute feature/orders-index-v2 --type read_only --cu 0.25
neon branches delete feature/orders-index-v2

set-default는 프로젝트의 기본 branch를 변경합니다. Vercel 통합처럼 default branch를 부모로 사용하는 기능도 영향을 받으므로 신중히 실행합니다. add-compute는 같은 branch에 compute를 하나 더 추가합니다. read replica는 같은 pageserver의 데이터를 읽으므로 별도의 데이터 복사가 없습니다.

reset, restore, set-expiration은 4.4 Instant Restore, Reset, Snapshot에서 시나리오와 함께 설명합니다.

연결 문자열

neon connection-string feature/orders-index
neon connection-string feature/orders-index --pooled
neon connection-string feature/orders-index --database-name app --role-name app_rw

--pooled를 추가하면 connection pooler를 경유하는 호스트가 출력됩니다. serverless 함수처럼 연결이 많이 생기는 환경에서는 pooled 문자열을 사용합니다. LISTEN이나 prepared statement에 의존하는 도구는 직접 연결을 사용합니다.

schema-diff

neon branches schema-diff main feature/orders-index --database app
neon branches schema-diff main feature/orders-index@2026-09-01T00:00:00Z

두 branch의 schema를 비교해 SQL diff를 출력합니다. 두 번째 인자에 @timestamp 또는 @lsn을 추가하면 과거 시점과 비교합니다. migration 리허설 뒤 무엇이 바뀌었는지 확인하는 용도입니다.

REST API 대응

CLI 명령은 https://console.neon.tech/api/v2 아래의 endpoint를 호출합니다. branch 생성은 다음과 같습니다.

curl -s -X POST "https://console.neon.tech/api/v2/projects/$PROJECT_ID/branches" \
-H "Authorization: Bearer $NEON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"endpoints": [{"type": "read_write"}],
"branch": {
"parent_id": "br-wispy-dew-591433",
"name": "feature/orders-index",
"expires_at": "2026-09-14T00:00:00Z"
}
}'

branch 객체에 들어가는 필드는 다음과 같습니다.

필드
parent_id부모 branch ID (br- 접두어)
namebranch 이름
parent_lsn이 LSN 시점의 부모 상태에서 분기
parent_timestamp이 시각의 부모 상태에서 분기 (RFC 3339)
init_sourceparent-data(기본), parent-schema, schema-only, import
expires_at자동 삭제 시각

endpoints 배열을 비우면 compute가 없는 branch가 만들어집니다. 나중에 POST /projects/{id}/endpoints로 추가하거나 CLI의 add-compute를 사용합니다. parent_lsnparent_timestamp를 사용하면 control plane이 분기 시점을 처리합니다. 이는 Part III에서 pageserver API의 ancestor_start_lsn으로 직접 처리했던 작업입니다. 내부 구조는 2.4 Timeline과 Branch 내부를 참고합니다.

익명화한 데이터가 있는 branch는 이 endpoint의 init_source로 만들지 않습니다. 별도 endpoint인 POST /projects/{project_id}/branch_anonymized를 사용합니다. 어떤 컬럼을 어떻게 가릴지는 masking rule로 지정합니다. GitHub Action에도 masking_rules 입력이 있어 workflow에서 규칙을 JSON으로 전달합니다. 규칙 형식과 플랜 조건은 API 레퍼런스가 정본이므로 사용 전에 확인합니다. 익명화 데이터를 채우는 다른 방법은 4.5 Schema-only Branch와 민감 데이터에서 다룹니다.

조회와 삭제는 다음과 같습니다.

curl -s "https://console.neon.tech/api/v2/projects/$PROJECT_ID/branches" \
-H "Authorization: Bearer $NEON_API_KEY" | jq '.branches[] | {id, name, parent_id}'

curl -s -X DELETE "https://console.neon.tech/api/v2/projects/$PROJECT_ID/branches/$BRANCH_ID" \
-H "Authorization: Bearer $NEON_API_KEY"

CLI에 아직 없는 endpoint를 호출해야 하면 neon api 패스스루를 사용합니다. 인증 헤더는 CLI가 추가하므로 경로와 본문만 적습니다. HTTP method는 서브커맨드가 아니라 -X 옵션으로 지정합니다. 생략하면 GET이며, 본문을 주면 POST가 됩니다.

neon api /projects/$PROJECT_ID/branches
neon api /projects/$PROJECT_ID/branches -X POST -F branch.name=feature/x -F branch.parent_id=$PARENT_ID

플랜별 한도

항목FreeLaunchScale
포함 branch 수101025
프로젝트당 branch 상한10 (초과 생성 불가)5,0005,000
프로젝트당 root branch3525
보호 branch없음25
manual snapshot1100100
history window6시간 (1 GB 상한)최대 7일최대 30일
autoscaling 최대2 CU16 CU16 CU
고정 크기 compute 최대2 CU16 CU56 CU

포함 branch 수와 생성 상한은 서로 다른 값입니다. Free는 10개가 곧 상한이므로 11번째 생성은 실패합니다. Launch와 Scale은 포함량을 넘어도 생성이 제한되지 않습니다. 초과분에는 branch 단위 요금이 부과되며, 프로젝트당 5,000개가 상한입니다. 따라서 PR마다 branch를 만드는 팀이 유료 플랜에서 주의할 점은 생성 실패가 아닙니다. 삭제하지 않은 branch로 인한 누적 비용입니다. expiration을 지정하고 닫힌 PR의 branch를 삭제하는 자동화가 필요한 이유입니다.

--cu 범위는 autoscaling 최대치까지만 지정합니다. Scale의 56 CU는 고정 크기 compute에만 허용됩니다. 따라서 --cu 56처럼 단일 값으로 지정합니다. 한도와 가격은 플랜 정책에 따라 바뀌므로 최신 값은 플랜 문서에서 확인합니다.

흔한 실패

neon branches createbranches limit exceeded 계열 오류를 반환하면 상한을 초과한 것입니다. Free 플랜의 10개나 유료 플랜의 5,000개에 도달한 경우입니다. neon branches list로 삭제하지 않은 branch를 찾아 지웁니다. 유료 플랜에서 오류 없이 branch가 계속 만들어지는데 청구액이 늘어난다면 포함량을 넘긴 branch에 초과 요금이 부과된 것입니다.

neon connection-string이 호스트를 반환하지만 연결이 거부될 수 있습니다. compute가 scale to zero 상태에서 활성화되는 중일 가능성이 높습니다. 첫 연결에는 수백 ms에서 수 초까지 걸릴 수 있으므로 CI 스크립트에 재시도를 추가합니다.

API key를 코드 저장소에 넣지 않습니다. GitHub Actions에서는 secrets에 저장합니다. 로컬에서는 neon auth로 발급받은 자격 증명을 사용합니다.

연습 문제

  1. --no-compute로 branch를 만들고 add-compute로 read-only compute만 추가해 봅니다. 쓰기가 거부되는지 확인합니다.
  2. --output jsonjq로 부모가 없는 branch만 골라내는 한 줄 명령을 만듭니다.
  3. parent_timestamp로 1시간 전 상태의 branch를 API로 만들고, schema-diff로 현재 main과 비교합니다.

참고