← Files Fastly Agent ToolkitARCHIVED FILE

skills/fastly-fiddle/references/falco-vs-fiddle.md

3.93 KB · Oct 10, 2026 · 18:29 UTC

↓ Download file

# Falco vs Fiddle

Both test VCL. They're complementary, not interchangeable. SKILL.md's "When Fiddle, when Falco" table is the quick-decision reference; this file covers the reasoning behind it, the combined workflow, and the DSL differences.

One divergence worth internalizing: falco is a faithful Go reimplementation of Fastly's VCL dialect, not the real compiler. It catches almost everything, but divergences exist — especially around newly shipped VCL features. That gap is the core reason Fiddle stays in the loop despite being slower.

## Practical guidance

**Start in Falco.** Write subroutines, lint, run unit tests with mocks. This is where most bugs are caught and most iteration happens.

**Move to Fiddle when you need reality**:

- A `client.geo.*` branch you can't reasonably mock (mocking works for single-value checks; real geo data is useful when the logic traverses multiple fields).
- ESI logic, rate limiters, WAF rules.
- A bug you can only reproduce against real Fastly behavior — reproduce once in Fiddle, share the URL on a support ticket.
- Integration tests in CI that confirm the deployed-shape VCL behaves correctly end-to-end before you flip a service version live.

**Never use Fiddle for**:

- Fast TDD. You'll lose 15 seconds per iteration to edge sync.
- Any test you can express with falco mocks. The falco test is faster and more deterministic.

## Combined workflow

Ordered pipeline; each stage must pass (green) before the next runs:

1. falco lint — trigger: on edit. Speed: <1s, local.
2. falco test — trigger: lint passes. Speed: <1s per test, watch mode.
3. Fiddle CI run — trigger: falco tests green. Speed: 10-60s, real edge, pre-merge gate.
4. fastly deploy — trigger: Fiddle CI green. Target: staging service.

The Fiddle run is a gate, not an inner loop. Keep its test suite focused on assertions that only Fiddle can verify — don't duplicate every falco unit test in Fiddle form.

## Shared shape, different DSLs

The two tools have **different assertion DSLs**. You cannot reuse test files between them.

| Concept            | Falco                                                | Fiddle                                                                  |
| ------------------ | ---------------------------------------------------- | ----------------------------------------------------------------------- |
| Equality           | `assert.equal(actual, 200)`                          | `clientFetch.status is 200`                                             |
| Substring          | `assert.contains(s, "x")`                            | `clientFetch.bodyPreview includes "x"`                                  |
| Subroutine called  | `assert.subroutine_called("my_helper")`              | `events.where(fnName=my_helper).count() is 1`                           |
| Origin fetch count | n/a (no real fetch)                                  | `originFetches.count() is 0`                                            |
| TTL set in fetch   | `assert.equal(beresp.ttl, 3600s)` in `@scope: fetch` | `events.where(fnName=fetch)[0].ttl isAtLeast 3600`                      |
| State / return     | `assert.state(lookup)`                               | `events.where(fnName=recv)[0].return is "lookup"`                       |
| Error raised       | `assert.error(404)`                                  | `clientFetch.status is 404` + `events.where(fnName=error).count() is 1` |

## One more thing: Fiddle as a remote linter

If your CI host can't install falco (no Go toolchain, no Homebrew, whatever), Fiddle's `POST /fiddle` returns structured lint diagnostics without executing. Costs one HTTP round trip.

```bash
curl -sS -X POST https://fiddle.fastly.dev/fiddle \
  -H 'Content-Type: application/json' \
  --data @fiddle.json | jq '{valid, lintStatus}'
```

Exit non-zero when `.valid == false`. See the `api.md` reference ("Lint-only workflow").

This is a fallback, not a replacement — falco's linter is faster, offline, and has richer rule configuration.

SHA-256: 768f51ac18387b27420005f6cde4a936178a84d8248d7a724a3b5dd91b31cb1e