Input References

When a block needs data from an upstream block, you list the upstream block's invocation ID in the inputs field. Spade supports two reference styles: bare references and explicit references. You can mix both styles in the same inputs list.

Bare references🔗

A bare reference is the simplest form. You provide only the invocation ID of the upstream block:

inputs:
  - "@upstream"

When Spade encounters a bare reference, it uses type matching to determine which output from the upstream block connects to which input on the current block. This works well when the connection is unambiguous -- for example, when the upstream block produces a single raster output and the current block expects a single raster input.

Example: unambiguous bare reference🔗

Consider two blocks:

  • data.sentinel2 produces one output: image (type: file, format: GeoTIFF)
  • raster.reproject expects one file input: raster (type: file, format: GeoTIFF)

The pipeline:

blocks:
  - id: "@source"
    name: data.sentinel2
    inputs: []
    args:
      region: "POLYGON((-122.5 37.5, -122.0 37.5, -122.0 38.0, -122.5 38.0, -122.5 37.5))"

  - id: "@reproject"
    name: raster.reproject
    inputs:
      - "@source"
    args:
      target_crs: "EPSG:4326"

Spade sees that data.sentinel2 produces a GeoTIFF output and raster.reproject expects a GeoTIFF input. There is exactly one way to match them, so the bare reference is sufficient.

Explicit references🔗

An explicit reference is an object with up to three keys:

KeyRequiredDescription
blockYesThe invocation ID of the upstream block
outputYesThe name of the specific output to use
asNoThe name of the input on the downstream block to connect to. If omitted, Spade type-matches the named output against the current block's remaining unmatched inputs.
inputs:
  - block: "@classify"
    output: classified_raster

Explicit references are necessary when a bare reference would be ambiguous. This happens when the upstream block produces multiple outputs of the same type, or when there are multiple upstream blocks whose outputs could match the same input.

as is necessary on top of block+output in a further, more specific case: when two or more explicit references in the same inputs list target outputs that share a type, and the current block has two or more unmatched inputs of that same type. Naming the output alone doesn't tell Spade which of those same-typed inputs to wire it to -- see the raster.band-ratio example below.

Example: explicit reference needed🔗

Consider a block called raster.split-bands that produces two outputs:

  • red (type: file, format: GeoTIFF)
  • nir (type: file, format: GeoTIFF)

And a downstream block raster.band-ratio that expects two inputs:

  • numerator (type: file, format: GeoTIFF)
  • denominator (type: file, format: GeoTIFF)

Using bare references here would be ambiguous -- Spade cannot determine which output (red or nir) maps to which input (numerator or denominator). Naming the output with block+output alone is not enough either: both numerator and denominator are GeoTIFF, so after fixing nir and red as the two outputs, there would still be two equally valid ways to pair them with the two remaining GeoTIFF inputs. You need as to pin each one directly:

blocks:
  - id: "@split"
    name: raster.split-bands
    inputs:
      - "@source"
    args:
      red_band: 4
      nir_band: 8

  - id: "@ratio"
    name: raster.band-ratio
    inputs:
      - block: "@split"
        output: nir
        as: numerator
      - block: "@split"
        output: red
        as: denominator
    args: {}

Here, as wires the nir output directly to the numerator input and the red output directly to the denominator input -- no type matching is needed for either reference, so there's no ambiguity to resolve.

Mixed references🔗

You can combine bare and explicit references in the same inputs list. This is useful when some connections are unambiguous and others are not.

blocks:
  - id: "@combine"
    name: analysis.combine
    inputs:
      # Bare reference: the upstream block has one output that
      # matches one of this block's inputs by type.
      - "@imagery"

      # Explicit reference: this upstream block has multiple
      # outputs, so we name the specific one we want.
      - block: "@stats"
        output: summary_stats

Spade resolves explicit references first, then resolves the remaining bare references against the unmatched inputs.

Type-matching algorithm🔗

When Spade processes a block's inputs list, it runs the following algorithm to wire upstream outputs to the current block's declared inputs:

Step 1: Gather declared inputs. Read the current block's manifest to find all declared inputs and their types. Separate file-type inputs (which come from upstream blocks) from scalar inputs (which come from args).

Step 2: Resolve explicit references. For each explicit reference in the inputs list:

  1. Look up the upstream block invocation by its block ID.
  2. Look up the named output in that upstream block's manifest.
  3. If the reference has an as key, wire the output directly to the named input and mark both as resolved -- skip to the next reference. No type matching needed.
  4. Otherwise, find the declared input on the current block whose type is compatible with the output's type.
  5. If exactly one input matches, wire them together and mark both the output and the input as resolved.
  6. If no input matches, report a type-mismatch error.
  7. If multiple inputs match, report an ambiguity error and suggest adding as to pin the target input explicitly.

Step 3: Resolve bare references. For each bare reference in the inputs list:

  1. Look up the upstream block invocation by its ID.
  2. Collect all of that block's outputs that have not yet been resolved.
  3. For each unresolved output, find all unresolved inputs on the current block with a compatible type.
  4. If there is exactly one way to pair all unresolved outputs to unresolved inputs, wire them and mark them as resolved.
  5. If multiple pairings are possible, report an ambiguity error and suggest using explicit references.
  6. If an output has no compatible unresolved input, report a type-mismatch error.

Step 4: Verify completeness. After resolving all references, check that every required file-type input on the current block has been wired to an upstream output. If any required input remains unwired, report a missing-input error.

Walkthrough: unambiguous resolution🔗

Suppose Block A produces:

  • image (type: file, format: GeoTIFF)

And Block B expects:

  • raster (type: file, format: GeoTIFF)
  • threshold (type: number, from args)

Block B's pipeline entry:

- id: "@classify"
  name: raster.classify
  inputs:
    - "@source"
  args:
    threshold: 0.5

Resolution proceeds as:

  1. Declared file-type inputs: raster (GeoTIFF). Scalar inputs: threshold (from args).
  2. No explicit references.
  3. Bare reference to Block A. Block A has one unresolved output: image (GeoTIFF). Block B has one unresolved file-type input: raster (GeoTIFF). Types are compatible. Exactly one pairing exists. Wire image to raster.
  4. All required inputs are satisfied.

Walkthrough: ambiguous resolution🔗

Suppose Block A produces:

  • red (type: file, format: GeoTIFF)
  • nir (type: file, format: GeoTIFF)

And Block B expects:

  • band_a (type: file, format: GeoTIFF)
  • band_b (type: file, format: GeoTIFF)

Block B's pipeline entry using bare references:

- id: "@difference"
  name: raster.difference
  inputs:
    - "@split"
  args: {}

Resolution proceeds as:

  1. Declared file-type inputs: band_a (GeoTIFF), band_b (GeoTIFF).
  2. No explicit references.
  3. Bare reference to Block A. Unresolved outputs: red (GeoTIFF), nir (GeoTIFF). Unresolved inputs: band_a (GeoTIFF), band_b (GeoTIFF). Both outputs are compatible with both inputs. Two possible pairings exist: (red->band_a, nir->band_b) or (red->band_b, nir->band_a).
  4. Ambiguity error. Spade reports the conflict and suggests using explicit references.

The fix is to use explicit references:

- id: "@difference"
  name: raster.difference
  inputs:
    - block: "@split"
      output: nir
    - block: "@split"
      output: red
  args: {}

When to use each style🔗

SituationRecommended style
Upstream block has one output and downstream block has one matching inputBare reference
Upstream block has multiple outputs of different typesBare reference (types are still distinguishable)
Upstream block has multiple outputs of the same typeExplicit reference
Multiple upstream blocks produce outputs of the same type for a multi-input blockExplicit reference
You want maximum clarity regardless of ambiguityExplicit reference

As a general rule: start with bare references for simplicity. If spade check reports an ambiguity error, switch to explicit references for the affected connections.