Quickstart

Grid Quickstart

Grid Quickstart

Goal: write your first Grid model and see it compute. About 10 minutes.

Prerequisites

You need:

  • Node.js 20+
  • A clone of the Grid repo
  • npm install already run in the repo root

This walkthrough uses local validation, so you can see the model compute without configuring deployment infrastructure.

1. Write Your First Cells

Create a file hello.grid anywhere:

A1 = 10
A2 = 20
A3 = A1 + A2

That's already a valid model. A3 evaluates to 30 whenever A1 or A2 change.

Compile it to see what Grid produces:

npm run compile:model hello.grid

You'll see a generated runtime artifact printed to stdout. The compile step parses, builds the dependency graph, and confirms the model can run.

2. Add A Header

Real models start with a metadata header. Update hello.grid:

MODEL "Hello"
DESCRIPTION "A first Grid model."
VERSION "0.1.0"
AUTHOR "you@example.com"
 
A1 = 10
A2 = 20
A3 = A1 + A2
 
END MODEL

The header has no semantic effect on cell values, but it's required by linters and the canonical style guide.

3. Use Functions And Type Tags

Replace the body with this:

A1 as currency = 125000
A2 as currency = 86000
B1 as currency = A1 - A2
B2 as percentage = B1 / A1
B3 = ROUND(B2 * 100, 1)

What just happened:

  • as currency and as percentage are type tags. They tell consumers (formatters, validators, the UI) what the value means semantically.
  • ROUND is one of 548 built-in functions. See functions.md for the full catalog.
  • B2 will format as a percentage in the UI; B3 will format as a plain number rounded to 1 decimal place.

4. Branch With THEN ... ELSE

Grid's preferred conditional is THEN ... ELSE:

C1 = B1 > 50000 THEN "strong" ELSE "watch"

For multiple tiers, chain right-to-left from most-specific to least-specific (chained THEN ... ELSE must be on one line):

C2 = B2 > 0.5 THEN "great" ELSE B2 > 0.3 THEN "good" ELSE "weak"

If you're matching the same value against several alternatives, use MATCH:

C3 = MATCH(C1, "strong" -> :green, "watch" -> :amber, _ -> :red)

MATCH is a function call, so it can also wrap across lines:

C3 = MATCH(C1,
  "strong" -> :green,
  "watch"  -> :amber,
  _        -> :red
)

Multi-line rule. Grid is line-oriented at the top level, but any expression inside (...), [...], or {...} may span multiple lines. Block forms — DO, CASE WHEN, WHEN/EVERY/AT, WITH — also span lines. See reference.md.

The :green, :amber, :red are symbol literals — enum-like labels.

5. Local Bindings With DO

When a formula gets long, name intermediate values with DO ... END:

B4 as currency = DO
  margin = B1
  deduction = 2500
  MAX(margin - deduction, 0)
END

The last expression in a DO block is the value of the block.

6. Handle Missing Or Failing Values

Use DEFAULT for blank-or-error fallback:

A5 = BLANK
B5 = A5 DEFAULT 0          # → 0

For division-by-zero or other errors, use IFERROR or TRY:

B6 = IFERROR(A1 / 0, "n/a")   # → "n/a"
B7 = TRY 10 / 0 ELSE 0        # → 0

See errors.md for the full error model.

7. Try Arrays

Grid arrays spill — a formula returning an array writes a rectangle of cells anchored at its target.

D1 = [120, 135, 142, 150, 168]     # spills into D1:D5 horizontally
E1 = D1 * 1.1                      # broadcasts; spills into E1:E5
F1 = SUM(D1#)                      # D1# is the entire spilled array

Higher-order helpers work with arrays:

G1 = MAP(D1#, x => ROUND(x * 1.05, 2))
G2 = REDUCE(0, D1#, (acc, x) => acc + x)
G3 = SCAN(0, D1#, (acc, x) => acc + x)

8. Call An External Function

External functions cross the runtime boundary — they enqueue a job and write back asynchronously. Three are built in: FX_RATE, HTTP_JSON, ML_SCORE.

H1 = FX_RATE("EUR", "USD")
H2 = ROUND(125000 * (H1 DEFAULT 1.08), 2)

While the worker is fetching the rate, H1 is queued or running, not ready. The DEFAULT 1.08 keeps H2 computable in the meantime.

For a value you only want to compute on demand, use ~=:

H3 ~= ML_SCORE([0.12, 0.18, 0.27, 0.43])

H3 will not enqueue work until something reads it.

See external-functions.md for the full async semantics.

9. Add A Rule

Rule blocks run on the Grid runtime. The scheduler orchestrates rule waves and arms smart wakeups for EVERY/AT schedules, so the same model behaves identically in local validation and hosted execution:

MODEL "Hello With Rules"
VERSION "0.2.0"
 
A1 = 0
 
WHEN A1 > 100 THEN
  C1 = "over-limit"
  C2 = NOW()
END

Whenever A1 becomes greater than 100, the rule fires atomically: both C1 and C2 are set in the same wave.

For periodic actions:

EVERY duration"PT15M" SKIP MISSED THEN
  E1 = E1 + 1
END

For a one-shot action at a specific time:

AT dt"2026-12-31T23:59:00Z" BACKFILL THEN
  G1 = TRUE
END

See rules-and-schedules.md for the full rule semantics, including missed-run policy.

10. Run It For Real

To deploy the model into a running Grid, use the API URL for your Grid:

curl -X POST https://<your-grid-url>/api/models \
  -H "Content-Type: application/json" \
  -d "{\"id\": \"hello\", \"source\": $(jq -Rs . < hello.grid)}"
 
curl https://<your-grid-url>/api/models/hello

To write an input value:

curl -X PUT https://<your-grid-url>/api/models/hello/input \
  -H "Content-Type: application/json" \
  -d '{"symbol": "A1", "value": 200000, "typeTag": "currency"}'

See docs/api/http_api.md for the full HTTP contract.

If you're an LLM agent generating Grid code from natural language, start at ai-agent-guide.md.