---
title: 发布
icon: upload
description: 将你的 Twenty 应用分发到应用市场，或进行内部部署。
---

## 概览

一旦你的应用已[在本地构建并完成测试](/l/zh/developers/extend/apps/getting-started/concepts)，你可以通过两种方式进行分发：

* **部署 tar 包** — 直接将你的应用上传到特定的 Twenty 服务器，以供内部或私有使用。
* **发布到 npm** — 将你的应用在 Twenty 应用市场上架，供任何工作区发现并安装。

两种路径都从同一个**构建**步骤开始。

## 构建你的应用

运行构建命令来编译你的应用，并生成适用于分发的 `manifest.json`：

```bash filename="Terminal"
yarn twenty dev:build
```

这会编译 TypeScript 源码，转译逻辑函数和前端组件，并将所有内容写入 `.twenty/output/`。 添加 `--tarball`，还可以生成用于手动分发或 publish 命令的 `.tgz` 包。

## 部署到服务器（tar 包）

对于你不希望公开的应用（专有工具、仅供企业使用的集成或实验性构建），你可以将 tar 包直接部署到某台 Twenty 服务器。

### 先决条件

在部署之前，你需要配置一个指向目标服务器的远程。 远程会将服务器 URL 和身份验证凭据本地存储在 `~/.twenty/config.json` 中。

添加远程：

```bash filename="Terminal"
yarn twenty remote:add --url https://your-twenty-server.com --as production
```

### 部署

一步构建并将你的应用上传到服务器：

```bash filename="Terminal"
yarn twenty app:publish --private
# To deploy to a specific remote:
# yarn twenty app:publish --private --remote production
```

### 共享已部署的应用

<Warning>
在多个工作区之间共享私有（tarball）应用是一项 **Enterprise** 功能。 在您的工作区拥有有效的 Enterprise 密钥之前，**Distribution** 选项卡将显示升级提示，而不是共享控件。 请前往 [设置 > 管理面板 > Enterprise](/settings/admin-panel#enterprise) 以启用。
</Warning>

通过 tar 包分发的应用不会出现在公共市场中，因此同一服务器上的其他工作区无法通过浏览发现它们。 一旦您的工作区升级到企业版计划，您就可以像这样分享已部署的应用：

1. 前往 **Settings > Applications > Registrations** 并打开你的应用
2. 在 **Distribution** 选项卡中，点击 **Copy share link**
3. 将此链接分享给其他工作区的用户 — 它会将他们直接带到该应用的安装页面

该分享链接使用服务器的基础 URL（不包含任何工作区子域），因此适用于该服务器上的任意工作区。

### 版本管理

在更新已部署的 tarball 应用时，服务器要求 `package.json` 中的 `version` 必须**严格高于**（按[语义化版本](https://semver.org)排序）当前已部署的版本。 在 tar 包存储之前，重新部署相同版本或推送更低版本都会被拒绝 — 你会在 CLI 中看到 `VERSION_ALREADY_EXISTS` 错误。

要发布更新：

1. 将 `package.json` 中的 `version` 字段递增（例如：`1.2.3` → `1.2.4`、`1.3.0` 或 `2.0.0`）
2. 运行 `yarn twenty app:publish --private`（或 `yarn twenty app:publish --private --remote production`）
3. 已安装此应用并在应用的 Settings 选项卡中启用自动升级的工作区会在后台自动升级；其他工作区会在其设置中看到可用的升级

<Note>
预发布标签按预期工作：将 `1.0.0-rc.1` 递增为 `1.0.0-rc.2` 是允许的，并且像 `1.0.0` 这样的正式发布会被正确识别为高于 `1.0.0-rc.5`。 `package.json` 中的版本本身必须是有效的 SemVer 字符串。
</Note>

{/* TODO: add screenshot of the Upgrade button */}

### 服务器版本兼容性

如果你的应用使用了特定 Twenty 服务器版本中引入的功能（例如在 v2.3.0 中新增的 OAuth 提供方），应当在 `package.json` 的 `engines.twenty` 字段中声明应用所需的最低服务器版本：

```json filename="package.json"
{
  "name": "twenty-my-app",
  "version": "1.0.0",
  "engines": {
    "node": "^24.5.0",
    "twenty": ">=2.3.0"
  }
}
```

该值是标准的 [semver 范围](https://github.com/npm/node-semver#ranges)。 常见模式:

| 范围                                 | 含义                                      |
| ---------------------------------- | --------------------------------------- |
| `>=2.3.0`                          | 任何 2.3.0 及以上的服务器                        |
| `>=2.3.0 \<3.0.0` | 2.3.0 或更高，但低于下一个主版本                     |
| `^2.3.0`                           | 与 `>=2.3.0 \<3.0.0` 相同 |

**在部署和安装时会发生什么：**

* 如果已设置 `engines.twenty`，且目标服务器的版本不满足该范围，则部署（tarball 上传）或安装将被拒绝，并返回 `SERVER_VERSION_INCOMPATIBLE` 错误以及一条同时指明所需范围和实际服务器版本的消息。
* 如果 `engines.twenty` **未设置**，则该应用可在任何服务器版本上被接受（与现有应用向后兼容）。
* 如果服务器未配置 `APP_VERSION`，则跳过该检查。

<Note>
服务器是权威校验方——它会在 tarball 上传和工作区安装时验证 `engines.twenty`。 即使你通过带外方式部署 tarball 或从应用市场安装，服务器仍会强制执行兼容性要求。
</Note>

## 自动化 CI/CD（脚手架生成的工作流）

使用 `create-twenty-app` 生成的应用开箱即带有三个 GitHub Actions 工作流，位于 `.github/workflows/`。 CI 可在无需任何设置的情况下运行，CD 只需要配置一个 secret，而发布到 npm 只需进行一次性的 npm trusted-publisher 设置。

### CI — `ci.yml`

它会在每次向 `main` 推送以及拉取请求上自动运行你的集成测试。

**作用:**

1. 检出你的应用源代码。
2. 使用 `twentyhq/twenty/.github/actions/spawn-twenty-app-dev-test@main` 组合 action 启动一个隔离的 Twenty 测试实例（相当于 CI 中的 `yarn twenty docker:start --test`）。
3. 启用 Corepack，从你的 `.nvmrc` 设置 Node.js，并使用 `yarn install --immutable` 安装依赖。
4. 运行 `yarn test`，并从启动的实例传入 `TWENTY_API_URL` 和 `TWENTY_API_KEY`，以便你的测试可以与真实服务器通信。

**配置选项:**

* `TWENTY_VERSION`（环境变量，默认 `latest`）— 通过在 `ci.yml` 中编辑它来固定 CI 使用的 Twenty 服务器版本。
* 并发按 `github.ref` 分组，并会在有新的推送时取消进行中的运行。

不需要任何机密——测试实例是临时的，只在作业持续期间存在。

### CD — `cd.yml`

在每次向 `main` 推送时将你的应用部署到已配置的 Twenty 服务器；当为拉取请求添加 `deploy` 标签时，也可从该拉取请求进行部署。

**作用:**

1. 检出 PR 的 head（针对已加标签的 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_URL`     | `cd.yml` 中的 `env`（默认值为 `http://localhost:3000`）          | 要部署到的 Twenty 服务器。 首次使用前将其更改为你真实的服务器 URL。 |
| `TWENTY_DEPLOY_API_KEY` | GitHub 仓库 **Settings → Secrets and variables → Actions** | 在目标服务器上具有部署权限的 API 密钥。                   |

<Note>
默认的 `TWENTY_DEPLOY_URL` 值 `http://localhost:3000` 只是占位符——从 GitHub 托管的 runner 无法访问任何资源。 在启用 CD 之前，将其更新为你服务器的公网 URL（或使用具有网络访问权限的自托管 runner）。
</Note>

**从 PR 触发预览部署:**

为拉取请求添加 `deploy` 标签。 在 `cd.yml` 中的 `if:` 守卫会使用该 PR 的 head 提交为其运行作业，使你能在合并前在目标服务器上验证更改。

### 发布 — `publish.yml`

当你推送版本标签（例如 `v1.0.0`）时，或从 Actions 选项卡中手动运行该工作流时，会将你的应用附带来源证明发布到 npm。

**作用:**

1. 检出你的应用，设置 Node.js，并更新 npm（受信任发布需要 npm 11.5.1 或更高版本）。
2. 运行 `yarn twenty app:publish`，它会构建应用并将 `.twenty/output` 发布到 npm。 在 CI 中，它会自动添加 `--provenance` 和 `--access public`，因此在工作流中不需要任何标志。

**一次性设置：**

在 npmjs.com 上打开你的包 > **Settings → Trusted Publisher**，并使用 `publish.yml` 工作流为此仓库注册（参见 [npm trusted publishing 文档](https://docs.npmjs.com/trusted-publishers)）。 带有 provenance 的发布会证明是哪个 GitHub 仓库构建了该包，这也同样是你在 Twenty 市场中声明应用所有权的方式。

<Note>
npm 仅接受来自**公共**源代码仓库的 provenance。 如果你从私有仓库发布，npm 会以 `E422 ...` 错误拒绝 OIDC provenance 包。 Unsupported GitHub Actions source repository visibility: "private"`错误。 要从私有仓库进行发布，请在发布步骤的`env`中将`TWENTY_APP_PUBLISH_DISABLE_PROVENANCE: 'true'`设置为退出 provenance（在脚手架生成的`publish.yml\` 中包含了一条已注释的提示）：

```yaml filename=".github/workflows/publish.yml"
      - name: Publish to npm
        env:
          TWENTY_APP_PUBLISH_DISABLE_PROVENANCE: 'true'
        run: yarn twenty app:publish
```
</Note>

### 固定可复用的 actions

`ci.yml` 和 `cd.yml` 工作流引用了 `@main` 上的可复用 actions，因此会自动获取 `twentyhq/twenty` 仓库中的 action 更新。 如果你希望构建具有确定性，请在每个 `uses:` 行中将 `@main` 替换为某个提交的 SHA 或发行标签。

## 发布到 npm

发布到 npm 可让你的应用在 Twenty 应用市场中被发现。 任何 Twenty 工作区都可以直接通过 UI 浏览、安装和升级应用市场中的应用。

### 要求

* 一个 [npm](https://www.npmjs.com) 账户
* 你在 `package.json` 的 `keywords` 数组中的 `twenty-app` 关键字（需要手动添加 — 在 `create-twenty-app` 模板中默认不包含）

```json filename="package.json"
{
  "name": "twenty-app-postcard-sender",
  "version": "1.0.0",
  "keywords": ["twenty-app"]
}
```

### 应用市场元数据

`defineApplication()` 配置支持可选字段，用于控制你的应用在市场中的展示方式。 使用 `logo` 和 `galleryImages` 来引用 `public/` 文件夹中的图片：

```ts src/application-config.ts
export default defineApplication({
  universalIdentifier: '...',
  displayName: 'My App',
  description: 'A great app',
  logo: 'public/logo.png',
  galleryImages: [
    'public/screenshot-1.png',
    'public/screenshot-2.png',
  ],
});
```

完整的市场字段列表（`author`、`category`、`aboutDescription`、`websiteUrl`、`termsUrl` 等）请参见“构建应用”页面中的 [defineApplication 折叠面板](/l/zh/developers/extend/apps/config/application#marketplace-metadata)。

#### 建议的图库图片尺寸

该市场会在固定的 `8:5` 容器中渲染 `galleryImages`（例如，`1600×1000 px`）。

<Note>
任意纵横比的图库图片都会完整显示，且绝不会被裁剪，但相对于 `8:5` 明显更高或更窄的图片，两侧会出现空白边。
</Note>

#### 图片大小限制

`logo` 和每个 `galleryImages` 文件大小不得超过 **10 MB**。 当 marketplace 重新托管你已发布的资源时，较大的文件将被跳过，因此将不会显示。

### 发布

```bash filename="Terminal"
yarn twenty app:publish
```

要在特定的 dist-tag（例如 `beta` 或 `next`）下发布：

```bash filename="Terminal"
yarn twenty app:publish --tag beta
```

### 应用市场的发现机制如何运作

Twenty 服务器会**每小时**从 npm 注册表同步其市场目录。

你可以立即触发同步，而无需等待：

```bash filename="Terminal"
yarn twenty dev:catalog-sync
# To target a specific remote:
# yarn twenty dev:catalog-sync --remote production
```

在应用市场中显示的元数据来自你的 `defineApplication()` 配置——参见上面的 [应用市场元数据](#marketplace-metadata)。

<Note>
如果您的应用未在 `defineApplication()` 中定义 `aboutDescription`，市场将自动使用 npm 上您的软件包的 `README.md` 作为关于页面内容。 这意味着您可以为 npm 和 Twenty 市场维护同一个 README。 如果您希望在市场中使用不同的描述，请显式设置 `aboutDescription`。
</Note>

### CI 发布

上文所述生成的 `publish.yml` 工作流会在打上版本标签时，自动将包连同 provenance 一并发布到 npm。 由于 `yarn twenty app:publish` 在 CI 中运行时会为你添加 `--provenance` 和 `--access public`，因此该工作流不需要任何 npm 标志——只需要一次性完成受信任发布者的设置。

对于其他 CI 系统（GitLab CI、CircleCI 等），先运行 `yarn install`，然后运行 `yarn twenty app:publish`。 当环境可以生成 OIDC 令牌时会发出 provenance，否则会自动跳过。

<Note>
**npm provenance** 会在你的 npm 列表中添加可信徽章，使用户可以验证该包是由公共 CI 流水线中的特定提交构建的。 它也同样是你在 Twenty 市场中声明应用所有权的方式。 有关详细信息，请参见 [npm provenance 文档](https://docs.npmjs.com/generating-provenance-statements)。
</Note>

## 安装应用

一旦应用已发布（npm）或已部署（tarball），各工作区就可以通过 UI 进行安装。

在 Twenty 的 **Settings > Applications** 页面中，既可以浏览也可以安装来自市场或通过 tarball 部署的应用。

{/* TODO: add screenshot of the UI when the app is registered */}

你也可以通过命令行安装应用：

```bash filename="Terminal"
yarn twenty app:install
```

<Note>
服务器在安装时强制执行 SemVer 版本控制，与部署时的规则一致：

* 尝试安装与工作区中已安装版本相同的版本将被拒绝，并返回 `APP_ALREADY_INSTALLED` 错误。
* 尝试安装低于当前已安装版本的版本将被拒绝，并返回 `CANNOT_DOWNGRADE_APPLICATION` 错误。

若要安装较新的版本，请先部署或发布它，然后重新运行 `yarn twenty app:install`。
</Note>
