Open specification · formerly DTQL

Queries you can read, diff, and trust.

TugQL is a portable, human-readable query language. It combines a clean SQL-like text syntax with a 1:1, lossless structured query tree representation (TugQT) serialized as plain YAML/JSON. Save a query, hand-edit it, diff it in version control, and execute it across backends without loss.

Read the spec See an example $ go get github.com/dal-go/dalgo/dtql
query.tugql TugQL
from users as u
select
  u.name,
  u.age as years
where
  u.age >= 18
  and (u.status in ('active', 'pending') or u.country == 'US')
order by
  u.name,
  u.age desc
limit 10
offset 20
01 — Why TugQL

A query is data. Treat it like data.

TugQL turns a query into an understandable, diffable document you can store, review, and version — portable across every backend it runs on.

Human-readable

Intuitive SQL-like authoring syntax for people, plus plain YAML/JSON query tree (TugQT) for tooling — anyone can inspect it, understand it, and edit it.

Lossless round-trip

Canonical query lowering reconstructs queries structurally equal to the source. Nothing is silently dropped, mangled, or approximated.

Schema-validated

Published with full JSON Schema validation (draft 2020-12). Any tool, in any language, can validate a query structure before execution.

Diff-friendly

Canonical formatting and deterministic tree serialization. Saved queries diff cleanly in Git and review like standard code.

Portable by design

TugQL exposes functionality that is portable across backends, so one query runs unchanged across Git, SQLite, PostgreSQL, or Firestore.

Not full SQL

A deliberately focused, well-defined portable subset. Unportable constructs are rejected explicitly rather than translated dangerously.

02 — Example

A query as TugQL & TugQT

Author in TugQL text syntax; persist or exchange as a TugQT structured query tree.

Authors write queries in TugQL text syntax — readable, compact, and SQL-like. Underneath, the parser produces TugQT (Tug Query Tree), a canonical, machine-readable representation.

Every node maps deterministically between syntax and tree. Malformed input or schema violations return actionable diagnostics with precise source spans.

Note on naming: TugQL was formerly known as DTQL. Existing DTQL documents and query files remain supported for backwards compatibility.
users.tugqt.yaml YAML
from:
  name: users
columns:
  - field: name
  - field: age
    as: years
where:
  and:
    - op: '>='
      left:
        field: age
      right:
        value: 18
    - or:
        - op: In
          left:
            field: status
          right:
            values:
              - active
              - pending
        - op: ==
          left:
            field: country
          right:
            value: US
orderBy:
  - field: name
  - field: age
    desc: true
limit: 10
offset: 20
03 — node → TugQT

Mapping

Each in-scope query node has a defined structured representation.

Query nodeTugQT representation
From over a root collectionfrom: { name, alias? }
Columnitem under columns: — an expression plus optional as:
Comparison{ op, left, right }
Group condition (And){ and: [ … ] }
Group condition (Or){ or: [ … ] }
Order expressionitem under orderBy: — an expression plus optional desc: true
Field reference{ field: <name> }
Constant{ value: <scalar> }
Array{ values: [ <scalar>, … ] }
Operator==, In, >, >=, <, <=
Limit / Offsetlimit: <int> / offset: <int>

An expression sets exactly one of field, value or values, which discriminates a field reference, a constant, or an array.

04 — covered subset

What TugQL represents

Single source collections or joined trees, selected columns, filter expressions, ordering, and paging. Anything out of scope is rejected — never silently dropped.

In scope

Collection sources · selected columns · comparison and And/Or group trees · ordering · limit / offset · joins · parameters. Expressions: field reference, constant, array. Operators: ==, !=, In, >, >=, <, <=, And, Or.

Out of scope (rejected)

Unbounded cartesian joins · arbitrary dialect-specific vendor syntax · untyped mutation operators outside schema authority. Serialization errors out — it never emits a document that loses query semantics.

Lossless & canonical

resolve(parse(text)) produces deterministic query trees; serialization is canonical, so saved queries diff cleanly across versions.

05 — where it runs

One query, many backends

TugQL is the portable query surface. It maps onto a data abstraction layer (DALgo) that adapts it to whatever storage sits underneath.

Because TugQL expresses the portable subset, a query written once behaves consistently whether resolving against a Git repository (inGitDB), an embedded SQLite file, a PostgreSQL database, or Firestore.

TugQLportable query language
DALgodata abstraction layer
inGitDB SQLite PostgreSQL Firestore

Save it. Diff it. Run it anywhere.

TugQL makes a query a first-class, reviewable artifact — readable by people, validated by tooling, and portable across the backends it runs on.