Modern analytics workbench for modern data teams

Stop stitching analysis across clients, notebooks, and BI tools.
Query, model, and assemble it all on one canvas.

Weekly sales — 2024 H1 test_postgres
WITH weekly AS (
  SELECT
    date_trunc ('week', sale_date)::date AS week,
    category,
    SUM(amount) AS revenue
  FROM sales_transactions
  WHERE sale_date >= '2024-01-01'
    AND sale_date < '2024-07-01'
  GROUP BY 1, 2
)
SELECT week, category, revenue,
  ROUND(100.0 * (revenue - lag (revenue)
    OVER (PARTITION BY category ORDER BY week)), 2) AS wow_pct
FROM weekly ORDER BY week, category;
156 rows · 4 columns
Weekly sales — 2024 H1 by category
84000 80500 77000 73500 70000 2024-01-01 2024-02-19 2024-04-08 2024-05-27
Books Electronics
TODO: check the Books dip around Apr 8 — promo gap?
Revenue Insight
H1 growth is driven by Books & Electronics, not Beauty

Across 2024 H1, weekly revenue in Books and Electronics climbs steadily, together adding the majority of incremental revenue. Beauty stays flat week over week.

Revenue by category · 2024 H1
weekly_sales_2024_h1
1SELECT
2 category,
3 SUM(revenue) AS revenue,
4 ROUND(AVG(wow_pct), 2) AS avg_wow
5FROM weekly_sales_2024_h1
6GROUP BY category ORDER BY revenue DESC
categoryrevenueavg_wow
Electronics$1.92M+3.4
Books$1.74M+2.1
Home$1.51M+1.0
Beauty$2.03M−0.2
postgres · 96 ms · 3 columns · 4 rows
Recommendation
Rebalance H2 inventory toward Electronics and Books — projected +18% category revenue at flat Beauty spend.

Every source your team touches.

Relational, warehouse, NoSQL, and streaming, queried side by side and joined in a single window.

SQL Console
prod_postgres
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
WITH weekly AS (
  SELECT
    region,
    date_trunc('week', sale_date)::date AS week,
    SUM(amount)   AS revenue,
    SUM(quantity) AS units
  FROM sales_transactions
  WHERE sale_date >= '2024-01-01'
  GROUP BY region, date_trunc('week', sale_date)
)
SELECT
  region,
  week,
  revenue,
  units,
  SUM(revenue) OVER (PARTITION BY region ORDER BY week)        AS running_rev,
  RANK()       OVER (PARTITION BY week ORDER BY revenue DESC)  AS rank
FROM weekly
ORDER BY week, rank;
Runs #1 [SQL Console] × Table Chart 100 Page 1
# regionVARCHARweekDATErevenueNUMERICunitsINT8running_revNUMERICrankINT4
1 West 2024-01-01 842150.00 3120 842150.00 1
2 Central 2024-01-01 731880.00 2845 731880.00 2
3 East 2024-01-01 689204.00 2610 689204.00 3
4 West 2024-01-08 871530.00 3240 1713680.00 1
5 Central 2024-01-08 764220.00 2970 1496100.00 2
6 East 2024-01-08 702940.00 2688 1392144.00 3
7 West 2024-01-15 858410.00 3196 2572090.00 1
8 Central 2024-01-15 779650.00 3012 2275750.00 2
9 East 2024-01-15 715300.00 2742 2107444.00 3
Postgres Postgres
MySQL MySQL
MariaDB MariaDB
MongoDB MongoDB
DuckDB DuckDB
Snowflake Snowflake
Redshift Redshift
ClickHouse ClickHouse
BigQuery BigQuery
Redis Redis
MSSQL MSSQL
Oracle Oracle
SQLite SQLite
Kafka Kafka
Mixpanel Mixpanel
Elasticsearch Elasticsearch
Trino Trino

A Figma-style canvas for your whole analysis.

A query tab answers one question and scrolls away. A canvas keeps the whole thing in view: SQL, charts, and notes on one infinite board, assembled by an agent that works from your schema.

Q2 activation — funnel & retention
48,210
Signups
31,940
Activated
66.3%
Activation rate
Q2 activation funnel warehouse
WITH signups AS (
  SELECT date_trunc ('week', created_at)::date AS cohort, user_id
  FROM users WHERE created_at >= '2024-04-01'
), act AS (
  SELECT user_id FROM events WHERE name = 'activated'
)
SELECT cohort,
  COUNT(*) AS signups,
  COUNT(a.user_id) AS activated
FROM signups s LEFT JOIN act a USING (user_id)
GROUP BY cohort ORDER BY cohort;
13 rows · 3 columns
Signups vs activated · by week
Signups Activated
Weekly retention by cohort
100 75 50 25 0 W0 W1 W2 W3 W4
Apr 01 Apr 08 Apr 15
activation_by_cohort
cohortsignupsactivatedrate
Apr 019,1206,04066.2%
Apr 089,7806,21063.5%
Apr 1510,2407,01068.5%
Apr 229,5606,12064.0%
Apr 299,5106,56069.0%
Retention settles around ~45% by W4 across every cohort.
Week-3 dip shows up in every cohort. Ship the day-14 nudge?
Apr 22 & 29 cohorts still maturing — revisit next week ✳

One query, joined across every source.

DataFusion, an in-process query engine, joins Postgres, Snowflake, Mongo and more in a single SQL statement, in memory, with no ETL pipeline.

revenue_by_country.sql cohorts.sql +
Run ⌘↵ DataFusion All Connections
12345678910111213
SELECT
  u.country,
  SUM(o.amount)     AS revenue,
  COUNT(e.event_id) AS events,
  MAX(s.last_seen)  AS last_active,
  AVG(f.predicted)  AS forecast
FROM postgres.public.users u
JOIN snowflake.sales.orders o   ON o.user_id = u.id
JOIN mongo.analytics.events e   ON e.user_id = u.id
JOIN redis.cache.sessions s     ON s.user_id = u.id
JOIN duckdb.main.forecasts f    ON f.country = u.country
GROUP BY u.country
ORDER BY revenue DESC
Table Chart DataFusion execution plan
Scan postgres · users 48.2K rows · 0.3s
Scan snowflake · orders 4.1M rows · 1.2s
Scan mongo · events 2.4M rows · 0.9s
Scan redis · sessions 318K rows · 0.2s
Scan duckdb · forecasts 1.9K rows · 0.1s
Hash Join users ⋈ orders 4.1M rows · 1.4s
Hash Join events ⋈ sessions 2.4M rows · 1.1s
Hash Join revenue ⋈ activity 8.6M rows · 1.9s
Hash Join ⋈ forecasts
Aggregate GROUP BY country
Result ORDER BY revenue

First-class dbt & SQLMesh, no context switch.

Open your project and Arris reads it natively. Trace lineage, run and test models, and inspect plans without leaving the workbench.

dim_customers.sql stg_orders.sql +
dbtdbt: Run +model Lineage Compile postgres prod_postgres
12345678910111213141516171819202122232425
{{ config(materialized='table', schema='marts') }}

WITH customers AS (
  SELECT * FROM {{ ref('stg_customers') }}
),
orders AS (
  SELECT * FROM {{ ref('stg_orders') }}
),
customer_orders AS (
  SELECT
    customer_id,
    COUNT(*) AS order_count,
    SUM(amount) AS total_amount
  FROM orders
  GROUP BY customer_id
)
SELECT
  c.customer_id,
  c.first_name,
  c.last_name,
  c.email,
  COALESCE(co.order_count, 0) AS order_count,
  COALESCE(co.total_amount, 0) AS total_amount
FROM customers c
LEFT JOIN customer_orders co ON c.customer_id = co.customer_id
Depth 1 2 3 Vertical
MODEL
stg_customers
customer_id
first_name
last_name
email
MODEL
stg_orders
order_id
customer_id
order_date
status
amount
amount_usd
MODEL CURRENT
dim_customers
customer_id
first_name
last_name
email
order_count
total_amount

Python & Jupyter, built right in.

When the question outgrows SQL, drop into a notebook next to your query tabs instead of switching to another tool.

notebook revenue_analysis.ipynb notebook cohorts.ipynb +
Ready 3.12.3 — ~/venvs/analysis/bin/python Create venv…
In [1]:
import numpy as np
import pandas as pd
In [2]:
rng = np.random.default_rng(42)
df = pd.DataFrame(
    "region": rng.choice(["North", "South", "East", "West", "Central"], 240),
    "units":  rng.integers(50, 500, 240),
    "price":  rng.uniform(8.0, 40.0, 240).round(2),
)
df["revenue"] = (df["units"] * df["price"]).round(2)
summary = df.groupby("region").agg(
    orders=("units", "size"), total_units=("units", "sum"),
    revenue=("revenue", "sum"), avg_price=("price", "mean")
).sort_values("revenue", ascending=False).round(2)
summary
regionorderstotal_unitsrevenueavg_price
East 58144211453341.12118.94
Central 57135741385595.84104.81
West 43114241226833.72187.53
North 42118661144996.79187.80
South 3910932977143.5296.45
In [3]:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 4))
for region, grp in df.groupby("region"):
    ax.plot(grp.month, grp.revenue, label=region)
ax.set_title("Monthly revenue by region")
ax.legend(); plt.tight_layout(); plt.show()
0 70 140 210 280 JanMarMayJulSepNov Monthly revenue by region North South

Schema-aware SQL generation.

Describe the query in plain English. Arris knows your schema and writes SQL that runs, ready for you to review and run.

AGENT Codex gpt-5.5
sales_transactions selection · 6 rows
Generate month-over-month profit changes from sales_transactions.
▸ read_schema public.sales_transactions · 14 columns indexed
Month-over-month profit — I bucket rows by month with date_trunc, sum the profit, then compare each month to the previous one using a LAG() window:
WITH monthly_profit AS (
  SELECT date_trunc('month', sale_date)::date AS month,
         SUM(profit) AS total_profit
  FROM sales_transactions GROUP BY 1
)
SELECT month, total_profit,
  total_profit - LAG(total_profit)
    OVER (ORDER BY month) AS profit_change
FROM monthly_profit ORDER BY month;
Insert at cursor Replace selection
Runs locally, read-only — review it, then insert.
Ask the agent… (⌘↵ to send)

One app, every tool you reach for.

Beyond the headline features, Arris ships the everyday essentials an analytical workbench should have.

Git integrationPinned queriesCode formatterSSH tunnelSchema browserIntegrated terminalMarkdown viewerCSV & JSON exportdbt / SQLMesh lineageGit integrationPinned queriesCode formatterSSH tunnelSchema browserIntegrated terminalMarkdown viewerCSV & JSON exportdbt / SQLMesh lineageGit integrationPinned queriesCode formatterSSH tunnelSchema browserIntegrated terminalMarkdown viewerCSV & JSON exportdbt / SQLMesh lineage

Frequently asked questions.

What is Arris?

Arris is an analytical workbench for your databases. It puts a SQL editor, schema browser, charts, and an AI agent on one infinite canvas, built for exploring data and building a whole analysis, not just running one query at a time.

How does Arris compare with other tools?

Arris does more than a database client. Where a traditional client runs a query and hands you a result grid, Arris keeps the whole analysis in view: SQL cells, charts, and notes assembled on a Figma-style canvas, with an agent that reads your schema and writes the query for you. It is an all-in-one analytics workbench.

What is the Canvas?

Canvas is an infinite board that holds an entire analysis. Live cells run real SQL, charts and tables bind to those queries and re-render the moment they run again, and sticky notes frame the story, all assembled by an agent that works from your schema. A query tab answers one question and scrolls away; a canvas keeps the whole investigation in one place.

Where does my data live?

Your connections and query results stay on your computer. The one exception is the AI features: when you ask the agent for help, the relevant schema and query context are sent to your chosen model provider (Claude or Codex) to generate a response, and only with your permission. Outside of that, Arris has no telemetry and nothing you do leaves your machine.

Which platforms does Arris run on?

Arris ships today as a desktop app for macOS, with native builds for both Apple Silicon and Intel, and more platforms are on the way. It is built on Tauri (a Rust core with a web-based UI), so it installs and runs like any other desktop app, with no website or browser tab to keep open.

Which databases can I connect to?

Arris ships 17 bundled drivers, including Postgres, MySQL, Snowflake, MongoDB, Redis, DuckDB, and SQLite, spanning SQL, NoSQL, and streaming sources.

How does querying across databases work?

An embedded DataFusion engine lets you write a single SQL statement that joins across multiple connections. Filters and projections are pushed down to each source, and only matching rows are streamed back to be joined locally.

How are my database credentials stored?

Passwords, SSH key passphrases, and tokens are saved to the macOS Keychain through the system Security framework, encrypted at rest and never written to disk in plain text. Connection settings live locally on your Mac.

Does it work with dbt and SQLMesh?

Yes. Arris understands dbt and SQLMesh projects natively: browse model lineage, run and test models, preview compiled SQL, and inspect plans without leaving the app.

Get Arris