blog.dopana

Back

If you have ever written a GitHub Actions pipeline, you probably know the pain of “YAML Fatigue”. You try to add a simple conditional step or run tests in parallel, only to find yourself struggling with indentation spacing, writing bash scripts inside multi-line strings, and committing 20 times just to debug.

With Cloudflare’s new native CI/CD system, YAML is out. TypeScript is in.

Because a CI/CD pipeline is essentially a set of step-by-step instructions, Cloudflare lets you configure it using type-safe TypeScript code. Here is a detailed, easy-to-understand walkthrough of how to write your configuration.

YAML vs TypeScript#

In a traditional setup, pipelines are static configuration strings. In Cloudflare CI Workflows, pipelines are active programs:

graph LR
    YAML["📄 Static YAML<br/>- No loops<br/>- No native functions<br/>- Heavy bash scripts"]
    TS["🦕 TypeScript Code<br/>- Loops & Try/Catch<br/>- Parallel execution<br/>- Full autocomplete"]
    
    YAML -->|Replaced by| TS

Writing a CI Pipeline in TypeScript#

Here is a full, detailed example of a CI/CD workflow configured in TypeScript.

Detailed Code Breakdown#

1. Installation & Caching#

deps = await ci.runner({
  name: 'install',
  command: 'bun install --frozen-lockfile',
  cache: { inputs: ['package.json', 'bun.lock'] },
});
typescript

Instead of manually caching directories, you pass a cache block pointing to your lockfile. Cloudflare automatically takes a sandbox snapshot of your dependencies and saves it to R2. If the lockfile doesn’t change, the next run loads instantly!

2. Parallel Executions#

await Promise.all([
  deps.runner({ name: 'lint', command: 'bun run lint' }),
  deps.runner({ name: 'test', command: 'bun run test' }),
  ...
]);
typescript

In YAML, running steps in parallel requires defining complex jobs and staging matrix rules. In TypeScript, you just use standard JavaScript Promise.all(). Cloudflare spins up isolated sandboxes for each command and executes them concurrently.

3. Self-Healing Try/Catch#

catch (failure) {
  if (isCiRunnerFailure(failure)) {
     // Trigger LLM Agent to write a patch branch automatically!
  }
}
typescript

If a unit test fails, instead of just sending an alert, the catch block catches the runner error, summons an AI agent (like Workers AI), reads the logs, writes a fix, commits it to a new branch, and suggests a pull request to the developer.

Triggering the Build (wrangler.toml)#

To hook up your repository push events to trigger this workflow, configure a trigger binding in your wrangler.toml file:

Whenever code is pushed to your Artifacts namespace, Cloudflare starts a new instance of your TypeScript workflow automatically.

References#