Signs you have outgrown it
What you get on the other side
SQL, not nested IFs
Analytical questions in a readable language. Joins across sources. Aggregations that run in milliseconds, not minutes.
A real database under the hood
Your data sits in Apache Iceberg on S3, queried by DuckDB. Handles tens of millions of rows without thinking about it.
Shareable URLs
A chart is a link. Publish once, the number updates automatically. Email a URL; everyone sees the same thing.
An API for your ops team
Save a query, call it via REST. Scripts, dashboards, and internal tools pull fresh numbers on demand.
Version control for data logic
Transforms are named objects with a history. Change the SQL, the chart updates everywhere that query is used.
How to move your data over
Path 1: export a CSV, push it once
For a one-shot migration, export the tab as CSV and push it to a table. The schema is inferred. Querying starts immediately.
# Install the CLIcurl -sSL rawquery.dev/install.sh | sh
# Push the CSVrq push sales_q1.csv --table sales
# Query itrq query "SELECT region, sum(revenue) FROM sales GROUP BY 1 ORDER BY 2 DESC"# Install the CLIcurl -sSL rawquery.dev/install.sh | sh
# Push the CSVrq push sales_q1.csv --table sales
# Query itrq query "SELECT region, sum(revenue) FROM sales GROUP BY 1 ORDER BY 2 DESC"Path 2: live Google Sheets connector
If the sheet keeps being updated (form responses, ops tracking, manual data entry), connect it directly. Every sync refreshes the table. Your spreadsheet stays the input surface; rawquery handles the queries and the charts.
rq connections create ops-tracker \ --type google-sheets \ -p service_account_json=@sa.json \ -p spreadsheet_id=1AbCdEfGhIjKlMnOpQrStUvWxYzrq connections sync ops-tracker
rq query "SELECT status, count(*) FROM ops_tracker.tickets GROUP BY 1"rq connections create ops-tracker \ --type google-sheets \ -p service_account_json=@sa.json \ -p spreadsheet_id=1AbCdEfGhIjKlMnOpQrStUvWxYzrq connections sync ops-tracker
rq query "SELECT status, count(*) FROM ops_tracker.tickets GROUP BY 1"Column names are normalized (lowercased, snake_cased). Run rq describe ops_tracker.tickets after the first sync to see the exact names.
When staying in Sheets is the right call
- Under ~10k rows. Sheets handles this comfortably. The overhead of a new tool is bigger than the problem.
- The workbook is the workflow. Forms, manual edits, conditional formatting, Apps Script macros: this is what Sheets is for. Keep it.
- Team is non-technical. If nobody on the team writes SQL and there is no intent to learn, Sheets with a well-structured summary tab beats a tool nobody touches.
- It is working fine. A spreadsheet that ships correct numbers on time is a good spreadsheet. The time to move is when it stops doing that, consistently.
Try the new shape
Free tier includes enough rows and queries to migrate a real workbook and see if the shape fits. No credit card.