Skip to main content

Lynx Flow Overview

Lynx Flow is LynxDB's query language. It is a pipeline language -- data flows left-to-right through a series of commands separated by | (pipe). Both the Lynx Flow surface syntax and SPL2 syntax are first-class citizens -- the parser accepts either, and they compile to the same AST and execution plan.

Lynx Flow is used everywhere in LynxDB -- CLI queries, REST API, materialized views, and saved queries. Learn it once, use it everywhere.

Pipeline Concept

from <source> | command1 args | command2 args | command3 args

Each command receives a stream of events, transforms it, and passes the result to the next command. This is analogous to Unix pipes:

# Unix: find | grep | sort | head
# Lynx Flow: from nginx | where status>=500 | group by uri compute count() | order by count desc | take 10

Canonical Pipeline Rhythm

Every Lynx Flow query follows the same top-down rhythm:

from <source>            -- 1. Where does data come from?
| search ... -- 2. Full-text / term-level pre-filter
| parse ... -- 3. Extract structure from raw text
| let ... -- 4. Derive new fields
| where ... -- 5. Filter rows
| group / every ... -- 6. Aggregate
| order by / take ... -- 7. Order and limit
| table / select ... -- 8. Shape output

Not every stage is required. A minimal query is just a source and a filter:

from nginx
| where status >= 500

Example Pipeline

from nginx
| parse combined(_raw)
| where status >= 500
| group by uri compute count() as hits, avg(duration_ms) as avg_latency
| order by hits desc
| take 10
| table uri, hits, avg_latency

This reads as:

  1. Source -- read nginx events
  2. Parse -- extract fields from combined log format
  3. Filter -- keep only 5xx errors
  4. Aggregate -- count hits and average latency by URI
  5. Order -- sort by hit count descending
  6. Limit -- top 10
  7. Present -- format output columns

Design Principles

Intent-Based Naming

Commands are named for what they do, not how they do it:

IntentLynx FlowSPL2 Equivalent
Derive a fieldleteval
Keep only these fieldskeepfields
Remove these fieldsomitfields -
First N rowstakehead
Aggregate by groupsgroup by ... computestats ... by
Time-bucket aggregationevery 5m computetimechart span=5m
Streaming window aggrunningstreamstats
Per-event global aggenricheventstats
Ordered projectionselect--
Parse structured formatsparse json(...)unpack_json
Extract regexparse regex(...)rex
Expand arraysexplodeunroll
Full sortorder bysort

One Stage = One Shape Transition

Each command transforms the data shape in exactly one way:

  • parse adds columns (extraction)
  • let adds or replaces columns (derivation)
  • where removes rows (filtering)
  • keep / omit removes columns (projection)
  • group collapses rows (aggregation)
  • order by reorders rows (ordering)
  • take limits rows (truncation)

Parse is a First-Class Step

Raw text is the starting point, not an afterthought. The parse command bridges _raw text and typed fields:

from nginx
| parse combined(_raw)
| where status >= 500

17 built-in formats: json, logfmt, syslog, combined, clf, regex, pattern, nginx_error, cef, kv, docker, redis, apache_error, postgres, mysql_slow, haproxy, leef, w3c.

Core + Sugar Layers

LayerPurposeExamples
CorePrimitive operations (1:1 with pipeline operators)from, parse, let, where, keep, omit, group, every, bucket, order by, take, join, running, enrich, table, pack
SugarConvenience shortcuts (desugar to core operators)top, bottom, rare, rank, topby, bottomby, latency, errors, rate, percentiles, slowest, lookup, head, tail, sort

Sugar commands have documented desugarings. Use core operators when you need more control.

Implicit Fields

Every event in LynxDB has these built-in fields:

FieldTypeDescription
_time / _timestampdatetimeEvent timestamp (auto-detected or assigned at ingest)
_rawstringOriginal raw text of the event
_sourcestringSource identifier (e.g., "nginx", "api-gateway")
_idstringUnique event ID (ULID, assigned at ingest)

Implicit FROM

If your query starts with | (bare pipeline), LynxDB automatically prepends from main:

-- These are equivalent:
| where level="error" | group compute count()
from main | where level="error" | group compute count()

SPL2 Compatibility

Lynx Flow and SPL2 are both first-class syntaxes. The parser accepts either and they compile to the same AST. You can mix them freely during migration.

-- Pure Lynx Flow
from nginx | where status >= 500 | group by uri compute count() as hits | order by hits desc | take 10

-- Pure SPL2
FROM nginx | where status >= 500 | stats count as hits by uri | sort -hits | head 10

-- Mixed (both valid)
from nginx | where status >= 500 | stats count as hits by uri | order by hits desc | take 10

When SPL2 syntax is used, advisory hints suggest the Lynx Flow equivalent (informational only).

Command Categories

CommandDescription
from / indexSelect data source
searchFull-text keyword search

Parsing

CommandDescription
parse <format>(...)Extract structure from raw text (17 formats)
explode / unrollExpand array fields into rows

Derivation & Filtering

CommandDescription
let / evalCompute new fields
whereFilter rows by expression
fillnullReplace null values

Field Shaping

CommandDescription
keep / fieldsInclude only listed fields
omit / fields -Exclude listed fields
selectOrdered projection with inline rename
renameRename fields

Aggregation

CommandDescription
group by ... compute / statsGrouped or global aggregation
every <span> compute / timechartTime-bucketed aggregation
bucket / binAdd time-bucket column
running / streamstatsStreaming window aggregation
enrich / eventstatsPer-event global aggregation

Ranking & Ordering

CommandDescription
order by / sortOrder results
take / headFirst N results
tailLast N results
rank top/bottomRow-level ranking
topby / bottombyGrouped metric ranking
top / bottom / rareFrequency ranking
dedupRemove duplicates

Combining Data

CommandDescription
joinJoin two datasets
lookupEnrich with a dataset (sugar for left join)
appendAppend results from subsearch
multisearchUnion multiple searches
transactionGroup related events

Presentation

CommandDescription
tableFormat output columns
xyseriesPivot to cross-tabulation
pack / pack_jsonAssemble fields into JSON

Domain Sugar

CommandDescription
latencyPercentile time-series for duration fields
errorsError analysis shortcut
rateEvent rate over time
percentilesMulti-percentile summary
slowestTop N by duration

Views & CTEs

CommandDescription
materializeCreate materialized view
viewsList/inspect materialized views
dropviewDelete a materialized view
$name = ...Define CTE (Common Table Expression)

Aggregation Functions

Used in group compute, every compute, running, enrich, stats, timechart, eventstats, and streamstats:

FunctionDescription
count()Count events
sum(field)Sum values
avg(field)Average value
min(field)Minimum value
max(field)Maximum value
dc(field)Distinct count
values(field)List distinct values
stdev(field)Standard deviation
perc50(field)50th percentile (median)
perc75(field)75th percentile
perc90(field)90th percentile
perc95(field)95th percentile
perc99(field)99th percentile
earliest(field)First value by time
latest(field)Last value by time

See Aggregation Functions for details.

Eval Functions

Used in let, eval, where, and any expression context:

FunctionDescription
if(cond, true, false)Conditional
case(c1,v1, c2,v2, ...)Multi-way conditional
coalesce(a, b, ...)First non-null value
tonumber(s)Convert to number
tostring(n)Convert to string
round(n, d)Round to d decimal places
substr(s, start, len)Substring
lower(s) / upper(s)Case conversion
len(s)String length
match(s, regex)Regex match
strftime(t, fmt)Format timestamp

See Eval Functions for the full list.

CTEs (Common Table Expressions)

Define reusable intermediate results:

$threats = from threat_intel
| where threat_type in ("sqli", "path_traversal")
| keep client_ip, threat_type;

$logins = from audit
| where type = "login" AND result = "failed"
| group by src_ip compute count() as failures;

from $threats
| join type=inner client_ip [from $logins | rename src_ip as client_ip]
| table client_ip, threat_type, failures

Quick Reference

For the complete command-by-command reference with syntax, examples, desugarings, and SPL2 equivalents, see the Lynx Flow Reference.

See Also