Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Migrating from Gelato

Gelato deprecated Web3 Functions on March 31, 2026, and the classic Automate task products are winding down with them. Time-based tasks, event listeners and recurring contract calls all have direct rflow equivalents — self-hosted, with exactly-once execution instead of best-effort. This page maps every Gelato concept and shows the one-command importer.

The one command

Export your task definitions as JSON (the same shape as the automate-sdk createTask / createBatchExecTask options, plus a chainId) and run:

rflow import gelato ./tasks.json --output ./my-project

The input file may hold one task object, an array of tasks, or { "tasks": [...] }:

tasks.json
[
  {
    "name": "Oracle Keeper",
    "chainId": 1,
    "trigger": { "type": 1, "cron": "*/10 * * * *" },
    "web3FunctionHash": "QmPXsYNiw...",
    "web3FunctionArgs": { "oracle": "0x71B9...4da", "currency": "ethereum" }
  },
  {
    "name": "Counter Increment",
    "chainId": 84532,
    "trigger": { "type": 0, "interval": 300000 },
    "execAddress": "0x5FbDB2315678afecb367f032d93F642f64180aa3",
    "execSelector": "0xe8927fbc",
    "dedicatedMsgSender": true
  }
]

trigger.type is the SDK's TriggerType enum — numeric (0 TIME, 1 CRON, 2 EVENT, 3 BLOCK) or the spelled-out string, both work.

The importer scaffolds a complete project (rflow.yaml, .env / .env.example, abis/, docker-compose.yml, MIGRATION-NOTES.md) that passes rflow validate as-is, with every unconvertible piece kept visible as a # TODO(rflow import) comment plus a MIGRATION-NOTES entry — nothing is silently dropped.

Concept map — Gelato gave you X, in rflow it is Y

GelatorflowImported automatically?
CRON triggerworkflow with a cron: trigger✅ expression verbatim
TIME trigger (interval ms)workflow with an interval: trigger✅ the millisecond cadence maps to every: faithfully (rflow is second-granular, so sub-second or non-round intervals round to the nearest second and are flagged)
EVENT trigger (filter.address + topics)workflow with an event: trigger⚠️ the topic hash can't be reversed into an event name — but if an ABI json next to the export (or in its abis/ dir) declares that topic0, the real event name + ABI are used; otherwise a placeholder is written and flagged
blockConfirmationstrigger confirmations: N
BLOCK trigger (every block)a block: triggerblock: { every: 1, network: ... }✅ raise every: to run less often
Classic task (execAddress + execSelector/execData)send_transaction step from a scaffolded relayer✅ selector-only calldata is flagged if the function takes arguments
Resolver contract (checker)read: step with assert: (or an if:) before the send❌ noted — port the checker logic
dedicatedMsgSendera named relayer — your workflows share one address per chain⚠️ new address: update onchain whitelists (rflow relayers ls shows it)
web3FunctionArgs / userArgsconstants:${{ constants.<name> }} in steps
Web3 Function TypeScript bodynative steps (read, http_call, send_transaction, notify) where they fit; otherwise keep the code and run it from a command: step❌ logic cannot auto-convert, but a command: step runs your preserved Web3 Function as-is — it returns JSON that a later send_transaction consumes, so rflow keeps signing/simulation/idempotency. A TODO placeholder keeps the workflow valid meanwhile
W3F secretssecrets: backed by .envmanual
Gelato executors + 1Balancethe embedded relayer: your own funded wallet, automatic gas bumping/rebroadcast, optional automatic_top_up✅ scaffolded (fund the new signer)

The two honest caveats

msg.sender changes. Gelato executed through its own executors / dedicatedMsgSender proxy. rflow sends from your relayer wallet — the importer scaffolds a fresh signer: plus a main relayer. Fund it and update any contract whitelist that expected the Gelato sender.

TypeScript does not become YAML. A Web3 Function is a real program; the importer converts the trigger faithfully and leaves a placeholder step naming the W3F hash or path to port. Most W3F bodies port in minutes: the offchain fetch becomes http_call:, the onchain check becomes read: + assert:, and the returned calldata becomes send_transaction: — which also gets you pre-flight simulation, idempotency keys and a durable journal for free.

Worked example

The five-minute counter task above becomes:

rflow.yaml (generated)
relayers:
  # scaffolded to replace Gelato's dedicated msg.sender
  main:
    networks: [base-sepolia]
 
workflows:
  counter-increment:
    trigger:
      interval:
        # Gelato interval: 300000ms
        every: 5m
    steps:
      - id: exec-call
        send_transaction:
          network: base-sepolia
          relayer: main
          to: "0x5FbDB2315678afecb367f032d93F642f64180aa3"
          data: "0xe8927fbc"
    on_failure: dead_letter

Then:

cd my-project
docker compose up -d   # postgres
vim .env               # rpc urls + fresh signer mnemonic
rflow validate
rflow start

For event tasks, drop the contracts' ABI json files next to your task export (or in an abis/ dir beside it) before importing — the importer matches each task's topic hash against them and writes the real event name + ABI. If none matched, finish the one flagged TODO: the topic hash is kept in a comment right above the placeholder, and the comment names the two helpers — rflow abi find-event <file|dir> <topic0> to match it against ABIs you already have, and rflow abi fetch --network <net> --address <0x..> to pull the verified ABI from sourcify/etherscan.

What you gain in the move

  • Exactly-once execution — every trigger occurrence is claimed once in Postgres, every send carries an idempotency key. Survives kill -9. See Reliability.
  • Pre-flight simulation on every send by default — reverts are caught before gas is spent, plus gas caps and assert_sim gates.
  • Reorg-aware event triggersconfirmations: 0 | N | finalized per trigger, with on_reorg: responses. See Reorgs.
  • Backtestingrflow replay rehearses a workflow over real historical blocks before it goes live; Gelato had no equivalent.
  • Human approval gates on transactions — see Approvals.
  • No per-execution fees — your infra, your RPC, open source.
  • Off-chain automations too — cron → HTTP → Telegram with zero networks configured.