Skip to main content
POST /nql/run is deprecated. Its replacement, POST /v1/nql/execute, accepts the same statements and returns the same errors, but what you get back is a different object — a workflow and a run instead of a job. This guide covers why the change was made and exactly what to update in a caller.
Deprecated does not mean removed. /nql/run continues to work; the support window will be announced separately.

Why the change

NQL execution now runs on the same workflow engine as the rest of the platform — one execution model instead of two. Most real requests are not one statement. Materializing an interactive query also needs a sample computed before anyone sees output. Registering a supplier dataset means creating mappings, then refreshing. Under the job model, the caller owned that orchestration: fire a job, poll it, decide whether to fire the next one, and work out what to do when step three of five fails. Every consumer reimplemented the same retry and partial-failure logic, slightly differently. A workflow makes the whole request one durable unit the platform owns. /v1/nql/execute is the single-statement case of that model, and the same task composes into larger multi-step workflows without the caller changing transport. Every execution is now a first-class run with an id, a status, start and close times, a cancel endpoint, and a schedule if it needs one — instead of a fire-and-forget job whose only control was request-cancellation. The trade-off is real: for a genuinely single-step request, /v1/nql/execute is more work than /nql/run. The created dataset is no longer in the response, and reaching the job id takes an extra call. The sections below show the patterns that close both gaps.

What changes

The statement set and the errors are unchanged. The two things that actually require code changes are reaching the job id and getting the created dataset.

Reaching the job id

The execute response has no job id. The workflow’s task creates the job shortly after the run starts, so you discover it through the jobs API:
Three things to know:
  • The field is job_id, not id. /nql/run returns the job id as id, so a straight port reads the wrong key and gets undefined rather than an error. This is the most likely source of a silent bug in this migration.
  • You may not need the job at all. GET /workflows/{workflow_id}/runs reports run status (running, completed, failed). If you only need to know whether the statement finished, the run is enough — skip /jobs entirely.
  • Correlation works in both directions. The job carries workflow_id and workflow_run_id pointing back at the workflow, and GET /jobs?workflow_id=<workflow_id> returns every job across all runs of that workflow. See Filtering by workflow.

Getting the created dataset

/nql/run returned the whole dataset inline for CREATE MATERIALIZED VIEW, so callers could update local state before the statement had run. /v1/nql/execute does not — the dataset does not exist yet when the response is sent. Two ways to get it, depending on whether you can wait:
  1. Await the run, then resolve the dataset by name. You named the view in the statement, so the name is already known to your code. Once the run reaches completed, look the dataset up by name.
  2. Poll the job and read the id out of its result. Once the job reaches completed:
    then GET /datasets/42558.
Either way the dataset arrives after the statement runs rather than with the response, so an optimistic “here is your new dataset” render has nothing to render until the run finishes.

Stop sending execution_cluster

Placement runs on compute pools now, and compute_pool_id is honored identically by both endpoints. execution_cluster is a legacy field that no longer decides where work runs, and it is not in the documented request schema for either endpoint. If your caller still sets it, that code is dead — the migration is a good moment to delete it.

Errors need no changes

Both endpoints return the same RFC 7807 problem documents: same status codes, same title, same detail, same debug. Only instance (/v1/nql/execute instead of /nql/run) and the per-request log_id differ. Existing error handling keeps working as-is. See Troubleshooting NQL for how to read these bodies.

Worked example

A complete migration sequence, trimmed to the interesting fields:

Executing NQL via the API

Full guide to /v1/nql/execute — parameters, tracking, and errors

Workflow Orchestration

Compose multi-step operations into one durable workflow

Tracking Job Status

Polling patterns, backoff, and job result handling

Troubleshooting NQL

Reading RFC 7807 error responses