메인 콘텐츠로 건너뛰기

개요

앱을 로컬에서 빌드하고 테스트하면, 배포 경로는 두 가지입니다:
  • 타르볼 배포 — 내부 또는 비공개 사용을 위해 특정 Twenty 서버에 앱을 직접 업로드합니다.
  • npm에 게시 — 모든 워크스페이스가 검색하고 설치할 수 있도록 Twenty 마켓플레이스에 앱을 등재합니다.
두 경로는 동일한 build 단계에서 시작합니다.

앱 빌드

앱을 컴파일하고 배포 준비가 된 manifest.json을 생성하려면 빌드 명령을 실행하세요:
yarn twenty dev:build
이는 TypeScript 소스를 컴파일하고, 로직 함수와 프런트 컴포넌트를 트랜스파일하며, 모든 항목을 .twenty/output/에 기록합니다. 수동 배포 또는 publish 명령을 위한 .tgz 패키지도 생성하려면 --tarball을 추가하세요.

서버에 배포(타르볼)

공개하고 싶지 않은 앱 — 독점 도구, 엔터프라이즈 전용 통합 또는 실험적 빌드 — 의 경우, 타르볼을 Twenty 서버에 직접 배포할 수 있습니다.

사전 준비

배포 전에 대상 서버를 가리키도록 구성된 원격이 필요합니다. 원격은 서버 URL과 인증 자격 증명을 로컬의 ~/.twenty/config.json에 저장합니다. 원격 추가:
yarn twenty remote:add --url https://your-twenty-server.com --as production

배포

앱을 한 번에 빌드하여 서버에 업로드:
yarn twenty app:publish --private
# To deploy to a specific remote:
# yarn twenty app:publish --private --remote production

배포된 앱 공유

워크스페이스 간에 비공개(타르볼) 앱을 공유하는 것은 엔터프라이즈 기능입니다. 워크스페이스에 유효한 엔터프라이즈 키가 있을 때까지 Distribution 탭에는 공유 컨트롤 대신 업그레이드 프롬프트가 표시됩니다. 이를 활성화하려면 설정 > 관리자 패널 > 엔터프라이즈로 이동하세요.
타르볼 앱은 공개 마켓플레이스에 나열되지 않으므로, 동일한 서버의 다른 워크스페이스는 탐색만으로는 이를 찾을 수 없습니다. 워크스페이스가 Enterprise 플랜을 사용 중이면, 배포된 앱을 다음과 같이 공유할 수 있습니다:
  1. 설정 > 애플리케이션 > 등록으로 이동하여 앱을 엽니다
  2. Distribution 탭에서 공유 링크 복사를 클릭합니다
  3. 이 링크를 다른 워크스페이스의 사용자와 공유하세요 — 해당 앱의 설치 페이지로 바로 이동합니다
공유 링크는 서버의 기본 URL(워크스페이스 하위 도메인 없이)을 사용하므로 서버의 모든 워크스페이스에서 동작합니다.

버전 관리

이미 배포된 타르볼 앱을 업데이트할 때, 서버는 package.jsonversion이 현재 배포된 버전보다 semver 순서 기준으로 엄격히 더 높아야 합니다. 동일한 버전을 다시 배포하거나 더 낮은 버전을 푸시하는 경우, 타르볼이 저장되기 전에 거부됩니다 — CLI에서 VERSION_ALREADY_EXISTS 오류가 표시됩니다. 업데이트를 릴리스하려면:
  1. package.jsonversion 필드를 올리세요(예: 1.2.31.2.4, 1.3.0, 또는 2.0.0)
  2. yarn twenty app:publish --private(또는 yarn twenty app:publish --private --remote production)를 실행합니다.
  3. 앱을 설치한 워크스페이스는 설정에서 사용 가능한 업그레이드를 확인할 수 있습니다
프리릴리스 태그는 예상대로 동작합니다: 1.0.0-rc.11.0.0-rc.2로 올리는 것은 허용되며, 1.0.0과 같은 최종 릴리스는 1.0.0-rc.5보다 더 높은 버전으로 올바르게 인식됩니다. package.json의 버전은 유효한 semver 문자열이어야 합니다.

서버 버전 호환성

앱이 특정 Twenty 서버 버전에서 도입된 기능(예: v2.3.0에 추가된 OAuth 공급자)을 사용한다면, package.jsonengines.twenty 필드를 사용하여 앱에 필요한 최소 서버 버전을 선언해야 합니다:
{
  "name": "twenty-my-app",
  "version": "1.0.0",
  "engines": {
    "node": "^24.5.0",
    "twenty": ">=2.3.0"
  }
}
값은 표준 semver 범위입니다. 일반적인 패턴:
범위의미
>=2.3.02.3.0 이상인 모든 서버
>=2.3.0 \<3.0.02.3.0 이상이지만 다음 메이저 버전 미만
^2.3.0>=2.3.0 \<3.0.0과 동일
배포 및 설치 시 동작:
  • engines.twenty가 설정되어 있고 대상 서버의 버전이 해당 범위를 충족하지 않으면, 배포(tarball 업로드) 또는 설치가 SERVER_VERSION_INCOMPATIBLE 오류와 함께 거부되며 필요한 범위와 실제 서버 버전을 모두 나타내는 메시지가 표시됩니다.
  • engines.twenty설정되어 있지 않으면, 앱은 모든 서버 버전에서 허용됩니다(기존 앱과 하위 호환).
  • 서버에 APP_VERSION이 구성되어 있지 않으면, 검사가 생략됩니다.
서버가 최종 검증을 수행합니다 — 타르볼 업로드와 워크스페이스 설치 모두에서 engines.twenty를 검증합니다. 타르볼을 별도 경로로 배포하거나 마켓플레이스에서 설치하더라도, 서버는 여전히 호환성을 강제합니다.

자동화된 CI/CD (스캐폴드된 워크플로)

create-twenty-app으로 생성된 앱은 .github/workflows/ 아래에 기본으로 두 개의 GitHub Actions 워크플로가 포함되어 있습니다. 저장소를 GitHub에 푸시하는 즉시 실행할 준비가 되어 있습니다 — CI에는 추가 설정이 필요 없고, CD에는 단 하나의 시크릿만 필요합니다.

CI — ci.yml

main으로의 푸시와 풀 리퀘스트마다 통합 테스트를 자동으로 실행합니다. 하는 일:
  1. 앱의 소스 코드를 체크아웃합니다.
  2. twentyhq/twenty/.github/actions/spawn-twenty-app-dev-test@main 컴포지트 액션을 사용해 격리된 Twenty 테스트 인스턴스를 생성합니다(CI에서 yarn twenty docker:start --test와 동등합니다).
  3. Corepack을 활성화하고, .nvmrc에 따라 Node.js를 설정하며, yarn install --immutable로 의존성을 설치합니다.
  4. 생성된 인스턴스에서 TWENTY_API_URLTWENTY_API_KEY를 전달하여 실제 서버와 통신할 수 있도록 yarn test를 실행합니다.
구성 옵션:
  • TWENTY_VERSION(환경 변수, 기본값 latest) — ci.yml에서 이 값을 수정하여 CI에서 사용하는 Twenty 서버 버전을 고정합니다.
  • 동시 실행은 github.ref로 그룹화되며, 새 푸시가 발생하면 진행 중인 실행을 취소합니다.
시크릿이 필요하지 않습니다 — 테스트 인스턴스는 일시적이며 작업이 진행되는 동안에만 존재합니다.

CD — cd.yml

매번 main으로 푸시될 때 구성된 Twenty 서버에 앱을 배포하며, deploy 라벨이 적용된 경우 풀 리퀘스트에서도 선택적으로 배포합니다. 하는 일:
  1. 라벨이 지정된 PR의 경우 PR 헤드, 아니면 푸시된 커밋을 체크아웃합니다.
  2. twentyhq/twenty/.github/actions/deploy-twenty-app@main를 실행합니다 — CI에서의 yarn twenty app:publish --private에 해당합니다.
  3. twentyhq/twenty/.github/actions/install-twenty-app@main를 실행하여 새로 배포된 버전을 대상 워크스페이스에 설치합니다.
필수 구성:
설정위치목적
TWENTY_DEPLOY_URLcd.ymlenv(기본값 http://localhost:3000)배포 대상 Twenty 서버입니다. 처음 사용하기 전에 실제 서버 URL로 변경하세요.
TWENTY_DEPLOY_API_KEYGitHub 저장소 Settings → Secrets and variables → Actions대상 서버에서 배포 권한이 있는 API 키입니다.
기본 TWENTY_DEPLOY_URLhttp://localhost:3000은 플레이스홀더이며 — GitHub 호스팅 러너에서는 아무 곳에도 도달하지 않습니다. CD를 활성화하기 전에 서버의 퍼블릭 URL로 업데이트하세요(또는 네트워크에 접근 가능한 셀프 호스티드 러너를 사용하세요).
PR에서 프리뷰 배포 트리거하기: 풀 리퀘스트에 deploy 라벨을 추가하세요. cd.ymlif: 가드는 해당 PR의 헤드 커밋을 사용해 그 PR에 대한 잡을 실행하므로, 머지 전에 대상 서버에서 변경 사항을 검증할 수 있습니다.

재사용 가능한 액션 고정하기

두 워크플로 모두 @main의 재사용 가능한 액션을 참조하므로, twentyhq/twenty 저장소의 액션 업데이트가 자동으로 반영됩니다. 결정적 빌드를 원한다면, 각 uses: 줄에서 @main을 커밋 SHA 또는 릴리스 태그로 바꾸세요.

npm에 게시

npm에 게시하면 Twenty 마켓플레이스에서 앱을 찾을 수 있게 됩니다. 모든 Twenty 워크스페이스는 UI에서 바로 마켓플레이스 앱을 탐색, 설치 및 업그레이드할 수 있습니다.

요구 사항

  • npm 계정
  • package.jsonkeywords 배열에 있는 twenty-app 키워드(수동으로 추가하세요 — create-twenty-app 템플릿에 기본적으로 포함되어 있지 않습니다)
{
  "name": "twenty-app-postcard-sender",
  "version": "1.0.0",
  "keywords": ["twenty-app"]
}

마켓플레이스 메타데이터

defineApplication() 구성은 마켓플레이스에서 앱이 표시되는 방식을 제어하는 선택적 필드를 지원합니다. public/ 폴더의 이미지를 참조하려면 logoUrlscreenshots를 사용하세요:
src/application-config.ts
export default defineApplication({
  universalIdentifier: '...',
  displayName: 'My App',
  description: 'A great app',
  logoUrl: 'public/logo.png',
  screenshots: [
    'public/screenshot-1.png',
    'public/screenshot-2.png',
  ],
});
마켓플레이스 필드 전체 목록(author, category, aboutDescription, websiteUrl, termsUrl 등)은 Building Apps 페이지의 defineApplication 아코디언을 참조하세요.

권장 스크린샷 크기

마켓플레이스는 screenshots를 고정된 8:5 컨테이너에 렌더링합니다(예: 1600×1000 px).
어떤 종횡비의 스크린샷이든 전체가 표시되며 잘리지 않습니다. 그러나 8:5보다 훨씬 세로로 길거나 가로로 좁은 경우 양쪽에 빈 띠가 표시됩니다.

게시

yarn twenty app:publish
특정 dist-tag(예: beta 또는 next)로 게시하려면:
yarn twenty app:publish --tag beta

마켓플레이스 검색 방식

Twenty 서버는 npm 레지스트리에서 마켓플레이스 카탈로그를 매시간 동기화합니다. 기다리지 않고 즉시 동기화를 트리거할 수 있습니다:
yarn twenty dev:catalog-sync
# To target a specific remote:
# yarn twenty dev:catalog-sync --remote production
마켓플레이스에 표시되는 메타데이터는 defineApplication() 구성에서 가져옵니다 — displayName, description, author, category, logoUrl, screenshots, aboutDescription, websiteUrl, termsUrl 같은 필드입니다.
앱에서 defineApplication()aboutDescription을 정의하지 않으면, 마켓플레이스는 소개 페이지 콘텐츠로 npm에 게시된 패키지의 README.md를 자동으로 사용합니다. 즉, npm과 Twenty 마켓플레이스 모두에서 하나의 README만 관리하면 됩니다. 마켓플레이스에서 다른 설명을 사용하려면 aboutDescription을 명시적으로 설정하세요.

CI 게시

모든 릴리스마다 자동으로 게시하려면 이 GitHub Actions 워크플로를 사용하세요(OIDC 사용):
name: Publish
on:
  release:
    types: [published]

permissions:
  contents: read
  id-token: write

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "24"
          registry-url: https://registry.npmjs.org
      - run: yarn install --immutable
      - run: npx twenty dev:build
      - run: npm publish --provenance --access public
        working-directory: .twenty/output
다른 CI 시스템(GitLab CI, CircleCI 등)에서도 동일한 세 가지 명령을 사용합니다: yarn install, yarn twenty dev:build, 그리고 .twenty/output에서 npm publish.
npm provenance는 선택 사항이지만 권장됩니다. --provenance 옵션으로 게시하면 npm 목록에 신뢰 배지가 추가되어, 사용자가 공개 CI 파이프라인의 특정 커밋에서 패키지가 빌드되었는지 확인할 수 있습니다. 설정 방법은 npm provenance 문서를 참고하세요.

앱 설치

앱이 게시(npm)되었거나 배포(타르볼)되면, 워크스페이스는 UI를 통해 이를 설치할 수 있습니다. Twenty UI의 설정 > 애플리케이션 페이지로 이동하면 마켓플레이스 앱과 타르볼로 배포된 앱을 모두 탐색하고 설치할 수 있습니다. 명령줄에서 앱을 설치할 수도 있습니다:
yarn twenty app:install
서버는 설치 시 semver 버전 규칙을 강제하며, 배포와 동일한 규칙을 적용합니다:
  • 워크스페이스에 이미 설치된 것과 동일한 버전을 설치하려고 하면 APP_ALREADY_INSTALLED 오류와 함께 거부됩니다.
  • 현재 설치된 것보다 낮은 버전을 설치하려고 하면 CANNOT_DOWNGRADE_APPLICATION 오류와 함께 거부됩니다.
더 최신 버전을 설치하려면 먼저 배포하거나 게시한 다음 yarn twenty app:install을 다시 실행하세요.