Artifacts のイベントで、Artifacts リポジトリに保存したプロジェクトをビルドしてデプロイできます。ユーザーやエージェントがコミットをプッシュすると、イベントが Workflow インスタンス を起動します。
Workflow 内では、@cloudflare/ci SDK で継続的インテグレーション(CI)パイプラインを定義し、依存関係のキャッシュ、チェックの実行、プロジェクトのビルドを行います。CI パイプラインの最後のステップで、出力を Worker または Workers for Platforms の User Worker にデプロイできます。
次のような場合に役立ちます。
- Artifacts に保存したアプリケーションコードを、自動でビルドしてデプロイする。
- プッシュごとに lint、型チェック、テストなどのチェックを実行する。
- ロックファイル(
pnpm-lock.yamlなど)が変わっていないときに、依存関係を再利用する。 - チェックまたはビルドが失敗したら、デプロイを止める。
- API トークンのアクセスをデプロイステップに限定する。
- 出力を Worker または Workers for Platforms の User Worker にデプロイする。
- リポジトリの変更をプッシュする — Artifacts リポジトリへの
git pushがartifacts.repo.pushedイベントを発行し、プッシュされたリポジトリ、ブランチ、コミットを識別します。 - CI Workflow を実行する — イベントが Workflow を開始します。Workflow はコミットをチェックアウトし、依存関係をインストールしてキャッシュし、ビルド、lint、型チェック、フォーマットなどの CI ステップを並列実行します。ステップが失敗すると、デプロイ前に Workflow が止まります。
- Worker をデプロイする — Workflow は、ビルドした Worker をアカウントへ直接デプロイするか、Workers for Platforms を使う場合は User Worker としてデプロイします。
CI ステップの定義には @cloudflare/ci SDK を使います。パイプライン構築を助けるツールは 2 つあります。
- Runners — 各
runner()呼び出しは、分離されたサンドボックスを起動し、シェルコマンドを実行します。ローカルやほかの CI ですでに使っているコマンドをそのまま使えます。各 runner は、自身のログ、状態、出力ファイルを記録します。 - Cache — runner の
cacheオプションは、インストール済み依存関係をキャッシュし、後続の実行で再インストールしないようにします。依存関係を決めるファイル(pnpm-lock.yamlなど)をcache.inputsに渡します。これらのファイルが変わっていないときは、SDK はコマンドを再実行せず、キャッシュした結果を復元します。
キャッシュされた runner は、サンドボックスの スナップショット を取り、後続の runner が再利用します。複数の runner が同じキャッシュ結果から分岐できます。たとえば lint、型チェック、テストの runner が、1 つのキャッシュ済みインストールを共有できます。
失敗した runner は ステップ設定 に従って再試行します。再試行回数、バックオフ、タイムアウトを定義できます。前のステップに依存する runner は、その再試行が成功するまで始まりません。設定した再試行上限に達すると、Workflow は Errored 状態で終了します。
依存関係のインストール、チェックの実行、プロジェクトのビルド、Worker のデプロイに runner と cache を使う Workflow の例は、次のとおりです。
import { CIWorkflow } from "./src/pipeline";
export class CI extends CIWorkflow {
async pipeline(_event, _step, ci) {
// Install once, then run independent checks from the shared snapshot.
const deps = await ci.runner({
name: "install",
command: "bun install --frozen-lockfile",
cache: { inputs: ["package.json", "bun.lock"] },
});
await Promise.all([
deps.runner({ name: "lint", command: "bun run lint" }),
deps.runner({ name: "test", command: "bun run test" }),
deps.runner({ name: "typecheck", command: "bun run typecheck" }),
deps.runner({ name: "build", command: "bun run build" }),
]);
await deps.runner({
name: "deploy",
command: "bun wrangler deploy",
cloudflareCredentials: {
accountId: this.env.CLOUDFLARE_DEPLOY_ACCOUNT_ID,
},
});
}
}import { CIWorkflow } from "./src/pipeline";
import type {
CiContext,
CiParams,
CiRunnerResult,
CloudflareArtifacts,
} from "./src/pipeline";
import type { WorkflowEvent, WorkflowStep } from "cloudflare:workers";
export class CI extends CIWorkflow {
protected async pipeline(
_event: WorkflowEvent<CiParams<CloudflareArtifacts>>,
_step: WorkflowStep,
ci: CiContext,
): Promise<void> {
// Install once, then run independent checks from the shared snapshot.
const deps: CiRunnerResult = await ci.runner({
name: "install",
command: "bun install --frozen-lockfile",
cache: { inputs: ["package.json", "bun.lock"] },
});
await Promise.all([
deps.runner({ name: "lint", command: "bun run lint" }),
deps.runner({ name: "test", command: "bun run test" }),
deps.runner({ name: "typecheck", command: "bun run typecheck" }),
deps.runner({ name: "build", command: "bun run build" }),
]);
await deps.runner({
name: "deploy",
command: "bun wrangler deploy",
cloudflareCredentials: {
accountId: this.env.CLOUDFLARE_DEPLOY_ACCOUNT_ID,
},
});
}
}ユーザーやエージェントが Artifacts リポジトリにコミットをプッシュすると、Artifacts は変更されたリポジトリ、ブランチ、コミットを識別するイベントを発行します。このイベントで Workflow インスタンスを起動し、CI パイプラインを実行します。パイプラインはコミットを自動でチェックアウトしてリポジトリをクローンしたあと、コードに従って依存関係のインストール、チェック、ビルド、Worker のデプロイを行います。
このガイドでは、それらの CI ステップを CIWorkflow という Workflow クラスで定義します。プッシュのたびにこの Workflow を自動開始するには、Wrangler 設定に cf.artifacts.repo.pushed トリガーを追加します。次も含めてください。
- R2 バインディング: キャッシュした依存関係のスナップショットを保存するバケット
- Container(および Durable Object)バインディング: 各
runner()ステップでサンドボックスにアクセスするためのコンテナバインディング - Workflows バインディング
- Artifacts バインディング
- Observability(任意): Workers observability で、CI ジョブを Workflow インスタンスとして確認します
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "<worker-name>",
"main": "src/index.ts",
"compatibility_date": "2026-06-16",
"compatibility_flags": ["nodejs_compat"],
"artifacts": [
{
"binding": "ARTIFACTS",
"namespace": "<artifacts-namespace>"
}
],
"containers": [
{
"class_name": "CiSandbox",
"image": "./Dockerfile",
"max_instances": 10,
"instance_type": "standard-4"
}
],
"durable_objects": {
"bindings": [
{
"name": "SANDBOX",
"class_name": "CiSandbox"
}
]
},
"workflows": [
{
"name": "<workflow-name>",
"binding": "CI_WORKFLOW",
"class_name": "CI"
}
],
"exports": {
"CiSandbox": {
"type": "durable-object",
"storage": "sqlite"
}
},
"r2_buckets": [
{
"binding": "BACKUP_BUCKET",
"bucket_name": "<backup-bucket-name>"
}
],
"triggers": {
"events": [
{
"type": "cf.artifacts.repo.pushed",
// filter is optional. If you don't set repoName we will run the same workflow for every push on any repo in your Artifacts namespace
"filter": {
"namespace": "CI",
"repoName": "my-repo"
},
"target": {
"scriptName": "<worker-name>",
"workflowName": "<workflow-name>"
}
}
]
},
"observability": {
"enabled": true,
"logs": {
"enabled": true
}
}
}"$schema" = "node_modules/wrangler/config-schema.json"
name = "<worker-name>"
main = "src/index.ts"
compatibility_date = "2026-06-16"
compatibility_flags = [ "nodejs_compat" ]
[[artifacts]]
binding = "ARTIFACTS"
namespace = "<artifacts-namespace>"
[[containers]]
class_name = "CiSandbox"
image = "./Dockerfile"
max_instances = 10
instance_type = "standard-4"
[[durable_objects.bindings]]
name = "SANDBOX"
class_name = "CiSandbox"
[[workflows]]
name = "<workflow-name>"
binding = "CI_WORKFLOW"
class_name = "CI"
[exports.CiSandbox]
type = "durable-object"
storage = "sqlite"
[[r2_buckets]]
binding = "BACKUP_BUCKET"
bucket_name = "<backup-bucket-name>"
[[triggers.events]]
type = "cf.artifacts.repo.pushed"
[triggers.events.filter]
namespace = "CI"
repoName = "my-repo"
[triggers.events.target]
scriptName = "<worker-name>"
workflowName = "<workflow-name>"
[observability]
enabled = true
[observability.logs]
enabled = trueWrangler 設定の [observability] は、パイプライン実行ごとの状態とログを記録します。どの段階が失敗したかを特定するには、Workflows ダッシュボードでインスタンスを確認します。
各 runner は自身の入力、出力、状態を表示するため、失敗したコマンドを特定できます。runner が失敗すると、Workflow はその出力を記録し、そのファイルを必要とする段階は開始しません。
Worker をデプロイするには、最後の runner() ステップに wrangler deploy を渡します。例: workspace.runner({ name: "deploy", command: "wrangler deploy" })。
User Worker をデプロイするには、最後の runner() ステップに wrangler deploy --dispatch_namespace <DISPATCH_NAMESPACE> を渡します。
トリガーの filter は任意です。repoName を設定すると、そのリポジトリへのプッシュだけが Workflow を開始します。repoName を省略すると、Artifacts 名前空間内の任意のリポジトリへのプッシュすべてで、同じ Workflow が動きます。
CI Workflow を 1 つ所有し、名前空間内のすべての顧客リポジトリに同じように適用したいプラットフォームに役立ちます。リポジトリごとにトリガーを維持する代わりに、共有の Workflow 1 つが、プッシュのたびに各リポジトリをビルド、チェック、デプロイします。
名前空間内のすべてのリポジトリで同じ Workflow を動かすには、トリガーの filter から repoName を外し、namespace だけを残します。
{
"triggers": {
"events": [
{
"type": "cf.artifacts.repo.pushed",
"filter": {
"namespace": "CI"
},
"target": {
"scriptName": "my-ci-worker",
"workflowName": "ci-workflow"
}
}
]
}
}[[triggers.events]]
type = "cf.artifacts.repo.pushed"
[triggers.events.filter]
namespace = "CI"
[triggers.events.target]
scriptName = "my-ci-worker"
workflowName = "ci-workflow"各プッシュは、変更されたリポジトリ、ブランチ、コミットごとに独自の Workflow インスタンスを開始します。同じ共有 Workflow 定義から、リポジトリごとに別の Worker をデプロイできます。