---
title: Quickstart
description: Install ROSQL and run your first robotics telemetry query in under 5 minutes
sidebar_position: 1
keywords: [rosql, quickstart, install, ros2, cli, query, robotics, parquet]
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Quickstart

Get ROSQL running against your ROS2 telemetry data in under 5 minutes.

## Install the CLI

<Tabs>
  <TabItem value="prebuilt" label="curl | sh" default>

```bash
curl -fsSL https://rosql.org/install.sh | sh
```

Linux x86_64, Linux arm64, macOS Intel, and macOS Apple Silicon. Installs to `~/.local/bin/` with the Parquet backend included.

  </TabItem>
  <TabItem value="brew" label="Homebrew (macOS)">

```bash
brew install robotopsinc/tap/rosql
```

Intel and Apple Silicon. Supports `brew upgrade rosql` and `brew uninstall rosql`.

  </TabItem>
  <TabItem value="cargo" label="cargo install">

```bash
# Parquet backend + CLI (recommended — no external database required)
cargo install rosql --features server,duckdb

# PostgreSQL + CLI
cargo install rosql --features server,postgres

# Both backends
cargo install rosql --features server,duckdb,postgres
```

All platforms including Windows. Requires Rust stable — [rustup.rs](https://rustup.rs).

  </TabItem>
  <TabItem value="source" label="Build from source">

```bash
git clone https://github.com/RobotOpsInc/rosql
cd rosql

# CLI with Parquet backend
cargo build --release --features server,duckdb --bin rosql

# CLI with PostgreSQL
cargo build --release --features server,postgres --bin rosql
```

  </TabItem>
</Tabs>

## Your first query — local Parquet files

No database server required. Point ROSQL at a directory of Parquet files from the [demo-agent](https://github.com/RobotOpsInc/rmw_robotops/tree/development/demo-agent) or any OTel exporter:

```bash
rosql query "FROM traces WHERE status = 'ERROR' SINCE 1 hour ago" \
  --backend parquet \
  --url ./telemetry/robotops_demo_agent/20260403-141530/
```

```
╭──────────────────────────────┬──────────────────┬──────────────────┬──────────────────────┬───────────────┬────────────┬─────────────╮
│ timestamp                    │ trace_id         │ span_id          │ span_name_col        │ service_name  │ duration   │ status_code │
├──────────────────────────────┼──────────────────┼──────────────────┼──────────────────────┼───────────────┼────────────┼─────────────┤
│ 2026-04-03T14:32:11.012Z     │ a3f1c9d2...      │ f0e1d2c3...      │ navigate_to_pose     │ bt_navigator  │ 1423187000 │ ERROR       │
╰──────────────────────────────┴──────────────────┴──────────────────┴──────────────────────┴───────────────┴────────────┴─────────────╯
```

Use `--format json` for programmatic consumption, or `--format csv` for export.

The `--url` directory must follow the demo-agent output layout:

```
<url>/
  traces/          *.parquet  →  otel_traces
  logs/            *.parquet  →  otel_logs
  metrics/         *.parquet  →  otel_metrics
  topic_messages/  *.parquet  →  topic_messages
  mcap_metadata/   *.parquet  →  mcap_metadata
```

### Query from S3

```bash
rosql query "FROM traces WHERE status = 'ERROR' SINCE 1 hour ago" \
  --backend parquet \
  --url s3://my-bucket/robot-01/robotops_demo_agent/20260403-141530/
```

Set standard AWS environment variables for credentials (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`). See [Driver Support →](./drivers) for the full credential reference.

## Your first query — PostgreSQL

If you have an OTel-compatible PostgreSQL database:

```bash
rosql query "FROM traces WHERE status = 'ERROR' SINCE 1 hour ago" \
  --backend postgres \
  --url postgresql://user:pass@localhost:5432/telemetry
```

## Cross-signal correlation

The killer feature: `DURING` correlates events across data sources in a single query.

Find navigation failures that happened while the battery was critically low:

```sql
SELECT trace_id, span_name_col, service_name, duration, status_code, span_attributes
FROM traces
WHERE status = 'ERROR' AND action_name = '/navigate_to_pose'
DURING(
  FROM topics WHERE topic_name = '/battery_state'
  AND fields['percentage'] < 15
)
SINCE 6 hours ago
```

```bash
rosql query "SELECT trace_id, span_name_col, service_name, duration, status_code, span_attributes
FROM traces
WHERE status = 'ERROR' AND action_name = '/navigate_to_pose'
DURING(
  FROM topics WHERE topic_name = '/battery_state'
  AND fields['percentage'] < 15
)
SINCE 6 hours ago" \
  --backend parquet \
  --url ./telemetry/robotops_demo_agent/20260403-141530/
```

## Message causality

Trace the full causality chain from any span ID:

```sql
TRACE 'a3f1c9d2e8b04f7a'
```

This walks `parent_span_id → span_id` recursively and returns all spans in the causality chain — something plain SQL has no primitive for.

## Compile to SQL

Inspect what ROSQL generates (no DB or `--url` needed):

```bash
rosql compile "FROM traces WHERE duration > 500 ms" --backend parquet
```

Output:
```sql
SELECT * FROM otel_traces
WHERE duration > 500000000
ORDER BY timestamp DESC
LIMIT 100
```

## As a Rust library

```bash
cargo add rosql
```

```rust
use rosql::{parse, drivers::{sql::SqlBackend, ExecOptions}};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Parquet backend — local or S3
    let backend = SqlBackend::from_parquet("./telemetry/robotops_demo_agent/20260403-141530/").await?;

    // Or PostgreSQL
    // let backend = SqlBackend::new("postgresql://user:pass@localhost/telemetry").await?;

    let query = parse("
        SELECT trace_id, span_name_col, service_name, duration, status_code
        FROM traces WHERE status = 'ERROR' AND action_name = '/navigate_to_pose'
        DURING(
          FROM topics WHERE topic_name = '/battery_state' AND fields['percentage'] < 15
        )
        SINCE 6 hours ago
    ")?;
    let result = backend.execute(&query, &ExecOptions::default()).await?;
    println!("{}", serde_json::to_string_pretty(&result)?);
    Ok(())
}
```

## Next steps

- [Driver Support →](./drivers) — Parquet backend, S3 credentials, PostgreSQL, MySQL
- [CLI reference →](./cli) — all commands and flags
- [Cookbook →](./cookbook) — more example queries
- [Schema reference →](./schema-reference) — required table structure
