Build decentralized workflows that combine off-chain computation with on-chain execution using the Chainlink Runtime Environment (CRE) SDK.
The Chainlink Runtime Environment enables developers to create workflows that:
- Fetch data from external APIs with built-in consensus
- Interact with blockchains across multiple networks
- Coordinate complex operations with triggers and scheduling
- Aggregate results from multiple data sources reliably
Perfect for building price feeds, automated trading strategies, cross-chain applications, and any workflow requiring reliable off-chain computation with on-chain execution.
This monorepo contains:
- @chainlink/cre-sdk - Main SDK for building CRE workflows
- @chainlink/cre-sdk-examples - Example workflows and patterns
- @chainlink/cre-sdk-javy-plugin - WebAssembly compilation tools
// Execute every 5 minutes
const cron = new cre.capabilities.CronCapability();
cron.trigger({ schedule: "0 */5 * * * *" });// Fetch with built-in consensus across nodes
const price = await cre.runInNodeMode(
fetchPriceData,
consensusMedianAggregation(),
)(config);// Read/write to any EVM chain
const evmClient = new cre.capabilities.EVMClient(
undefined,
BigInt("5009297550715157269"), // Ethereum Sepolia
);- 🔄 Multi-Node Consensus - Aggregate data from multiple sources reliably
- ⚡ Cross-Chain Support - Work with 200+ blockchain networks
- 📊 Built-in Aggregation - Median, mean, and custom consensus mechanisms
- 🛡️ Type Safety - Full TypeScript support with Zod validation
- 🎯 Event-Driven - Cron triggers, HTTP webhooks, and custom events
- 🔗 Viem Integration - Native support for Ethereum interactions
🏦 DeFi Applications
- Automated yield farming strategies
- Cross-chain arbitrage bots
- Dynamic rebalancing portfolios
- Liquidation protection systems
📊 Data Oracles
- Custom price feeds with multiple sources
- Weather data aggregation
- Sports scores and betting odds
- Real-world asset tokenization data
🔗 Cross-Chain Operations
- Bridge monitoring and alerts
- Multi-chain governance voting
- Cross-chain token transfers
- Unified liquidity management
CRE workflows compile from TypeScript to WebAssembly and run inside a Javy/QuickJS sandbox — not a full Node.js or browser runtime. The SDK ships a multi-layered type safety system that catches incompatible API usage at every stage: in the IDE, during type checking, and at build time.
The compilation pipeline (cre-compile) runs two validation passes before bundling and WASM compilation:
-
TypeScript type checking — Runs
tscagainst your workflow using the nearesttsconfig.json. Catches all standard TypeScript errors plus SDK-provided type restrictions (see below). -
Runtime compatibility validation — Performs AST-level static analysis to detect imports of restricted Node.js modules and usage of unavailable global APIs. This catches patterns that type-level checks alone can't cover, such as
require()calls, dynamicimport(), and usage inside.jsfiles.
cre-compile workflow.ts output.wasm
│
├─ Step 1: TypeScript type check (uses your tsconfig.json)
├─ Step 2: Runtime compatibility validation (always runs)
├─ Step 3: Bundle to JS
└─ Step 4: Compile to WASM
Every new workflow project ships with a recommended tsconfig.json:
The critical setting is "types": []. By default TypeScript auto-includes all @types/* packages from node_modules, which would expose full Node.js and Bun type definitions. Setting types to an empty array prevents this, so only types explicitly provided by @chainlink/cre-sdk are available. This means you get type errors the moment you try to use APIs that won't exist at runtime.
The SDK blocks imports from Node.js built-in modules that cannot run in the WASM sandbox. Both bare specifiers (crypto) and node:-prefixed forms (node:crypto) are covered.
Blocked modules: crypto, fs, fs/promises, net, http, https, child_process, os, stream, worker_threads, dns, zlib
All exports from these modules are typed as never, so your IDE shows errors immediately:
import { createHash } from "node:crypto";
// ^^^^^^^^^^ Type 'never' is not assignable to ...
// The import itself also triggers a build-time error:
// ❌ 'node:crypto' is not available in CRE workflow runtime.These restrictions are enforced at two levels:
- IDE/type-check time —
@deprecatedJSDoc annotations produce strikethrough text and warnings. Thenevertypes cause type errors at every call site. - Build time — The runtime compatibility validator walks the AST of your workflow and all transitively imported local files, catching every import syntax (
import,export ... from,require(),import()). This check always runs — even with--skip-type-checks.
Some global APIs that exist in browsers or Node.js are not available in the QuickJS runtime. The SDK overrides their type definitions with never types and @deprecated markers that point you to the correct CRE alternative:
| Restricted API | CRE Alternative |
|---|---|
fetch() |
cre.capabilities.HTTPClient |
setTimeout() |
cre.capabilities.CronCapability |
setInterval() |
cre.capabilities.CronCapability |
window, document |
Not applicable (no DOM) |
XMLHttpRequest |
cre.capabilities.HTTPClient |
localStorage, sessionStorage |
Not applicable (no persistent storage) |
// ❌ IDE shows strikethrough + deprecation warning:
// "@deprecated fetch is not available in CRE WASM workflows.
// Use cre.capabilities.HTTPClient instead."
const response = await fetch("https://api.example.com");
// ~~~~~ Error: Argument of type 'string' is not assignable to parameter of type 'never'
// ✅ Correct approach — use HTTPClient:
import { HTTPClient } from "@chainlink/cre-sdk";
const client = new HTTPClient();
const response = client.sendRequest({
url: "https://api.example.com",
method: "GET",
});The build-time validator also catches these via TypeScript's type-checker, including globalThis.fetch-style access. If you shadow a restricted name with your own variable (e.g. const fetch = myCustomFunction), the validator correctly ignores it.
The SDK provides type definitions for all APIs that are available in the QuickJS/WASM runtime:
- Text encoding:
TextEncoder,TextDecoder - Binary data:
Buffer(withalloc,from,concat, etc.) - Base64:
atob(),btoa() - URLs:
URL,URLSearchParams - Console:
console.log(),.warn(),.error(),.info(),.debug() - Utilities:
Math.random()(overridden with seeded ChaCha8 for determinism)
These are declared in global.d.ts and automatically available when you import @chainlink/cre-sdk.
The CRE CLI exposes a --skip-type-checks flag on the compile command. Use it when you need to compile a workflow that has TypeScript errors you're willing to accept:
# Normal compilation — type check + runtime validation + build
cre compile src/workflow.ts
# Skip TypeScript type checking only
cre compile src/workflow.ts --skip-type-checksWhat --skip-type-checks does:
- Skips the TypeScript type checker (
tsc) — your tsconfig errors won't block compilation.
What --skip-type-checks does NOT do:
- It does not skip the runtime compatibility validation. Imports of restricted Node.js modules (
node:crypto,node:fs, etc.) and usage of unavailable globals (fetch,setTimeout, etc.) will always block compilation, because these would cause runtime failures in the WASM sandbox.
# This workflow imports node:crypto — compilation fails regardless of the flag:
$ cre compile src/bad-workflow.ts --skip-type-checks
# ⚠️ Skipping TypeScript checks (--skip-type-checks)
# ❌ Unsupported API usage found in workflow source.
# CRE workflows run on Javy (QuickJS), not full Node.js.
# - src/bad-workflow.ts:1:25 'node:crypto' is not available in CRE workflow runtime.Under the hood, the SDK's cre-compile binary (bin/cre-compile.ts) parses the flag and passes it through the compilation pipeline. The flag controls whether assertWorkflowTypecheck() runs, while assertWorkflowRuntimeCompatibility() always executes regardless. The CRE CLI invokes this binary, so the flag semantics are identical whether you run cre compile --skip-type-checks or call the SDK's compilation API directly.
This monorepo uses:
- Bun - Package manager and TypeScript runtime
- Biome - Formatting and linting
- Javy - WebAssembly compilation
# Clone with submodules (for protobuf definitions)
git clone --recursive https://github.com/smartcontractkit/cre-sdk-typescript
cd cre-sdk-typescript
# Install dependencies
bun install
# Build packages and perform full health checks
bun full-checks# Development
bun build # Build all packages using turbo
bun check # Format and lint code using biome
bun format # Format code using biome
bun lint # Lint code using biome
bun typecheck # Type check all packages
bun full-checks # Build packages and perform full health checks
# Package-specific builds (run from packages/cre-sdk/)
bun generate:proto # Generate types from protobuf
bun generate:chain-selectors # Update chain selector types
bun generate:sdk # Generate all SDK types and codeFor detailed development setup, see individual package READMEs:
This project uses Git submodules for external dependencies:
# Clone with submodules
git clone --recursive https://github.com/smartcontractkit/cre-sdk-typescript
# Or initialize submodules after cloning
git submodule update --init --recursive
# Update submodules to latest
git submodule update --remoteCurrent submodules:
chainlink-protos- Protocol buffer definitions
See LICENSE in individual package directories.
{ "compilerOptions": { "lib": ["ESNext"], "target": "ESNext", "module": "ESNext", "moduleDetection": "force", "moduleResolution": "bundler", "strict": true, "noEmit": true, "types": [], // ... }, "include": ["src/**/*"], }