- Documentation
- Catalog — Database Tools & Streaming
- SQL Query — Catalog Databases
Last updated: April 24, 2026
SQL Query
Guara Cloud lets you run read-only SQL statements against your managed PostgreSQL and MySQL catalog services without ever exposing the database to the public internet. Queries run inside the cluster, results stream back through the platform API, and the same surface is available from both the dashboard and the CLI.
Where it works
| Catalog service | Supported |
|---|---|
| PostgreSQL | ✓ |
| MySQL | ✓ |
| MongoDB / Redis / NATS / others | — (no SQL surface) |
The service must be running and healthy. SQL access is part of the standard catalog feature set and follows the same project-membership rules as the rest of the dashboard.
Safety model
Every request runs inside an explicit read-only transaction (BEGIN READ ONLY for PostgreSQL, START TRANSACTION READ ONLY for MySQL). The platform also enforces:
| Limit | Value |
|---|---|
| Statement timeout | 30 s |
| Maximum query length | 50 KB |
| Maximum returned rows | 1 000 (server appends LIMIT) |
| Concurrent queries per user × service | 3 |
| Result cache TTL | 15 s |
A request can only carry one SQL statement. Compound or chained statements (SELECT 1; SELECT 2) are rejected up front. If your result hits the row cap the response carries truncated: true, and the CLI prints a yellow ⚠ result truncated line under the table.
Use it from the CLI
Two commands ship under the existing catalog topic:
guara catalog query # execute a SQL statement
guara catalog schema # list tables and columns
Both pick up the project + service from --project/--service, environment variables (GUARA_PROJECT, GUARA_SERVICE), or a .guara.json link file.
guara catalog query
Pass the SQL through --query, load it from a file with --file (alias -f, or - to read from stdin), or pipe it on stdin (auto-detected when stdin is non-TTY):
# Inline statement
guara catalog query --query "SELECT id, email FROM users LIMIT 10"
# From a .sql file
guara catalog query --file ./reports/active-users.sql --format csv > users.csv
# Piped from stdin (auto-detected when stdout is non-TTY)
cat ./reports/active-users.sql | guara catalog query --service my-postgres
Output formats — pick one with --format (TTY/file rendering):
--format | Result |
|---|---|
table (default) | Pretty cli-table3 table with a {rows} · {ms} footer (plus · cached @ {time} when the result was served from cache). |
csv | RFC-4180 escaped CSV (quotes around values that contain commas, quotes, or newlines). Cells starting with =, +, -, @, tab, or carriage return are prefixed with ' to neutralise spreadsheet formula injection — disable with --no-csv-safe if you need raw fidelity. |
tsv | Tab-separated values. Tabs and newlines inside cells are replaced with spaces so each row stays on one line. Same --no-csv-safe opt-out applies. |
Global output flags (apply regardless of --format):
| Flag | Result |
|---|---|
--json | Full SqlQueryResponse envelope — columns, rows, rowCount, truncated, executionTimeMs, fromCache, cachedAt. Bypasses --format. Raw control bytes from cells are preserved here so machine consumers see the truth. |
--quiet | The integer row count on a single line (handy for shell conditionals). Bypasses --format. |
ANSI/OSC control bytes inside string cells are stripped from the table/CSV/TSV renderings so a malicious value cannot move the cursor, spoof the terminal title, or mask hyperlinks. --json is the escape hatch when you need the original bytes.
guara catalog schema
guara catalog schema # list every table and its columns
guara catalog schema --filter users # narrow the table list (case-insensitive)
guara catalog schema --json | jq . # full machine-readable schema
guara catalog schema --quiet # one table name per line
Each table renders as its own block with a small column table (Column, Type, Constraint).
Error codes
The CLI maps the platform error codes to actionable hints. Each surfaces as a one-line Hint: underneath the red ✖ message and uses the standard CLI exit codes (1 for failure, 2 for auth).
| Code | When | What to do |
|---|---|---|
SQL_QUERY_SERVICE_NOT_CAPABLE | Service is not PostgreSQL/MySQL | Use a database service that lists sql-query in its capabilities. |
SQL_QUERY_SERVICE_NOT_RUNNING | Service is not running + healthy | Wait for the service to stabilise (guara services info). |
SQL_QUERY_TOO_LONG | Query exceeds 50 KB | Split the query, or load a smaller --file. |
SQL_QUERY_TIMEOUT | Query hit the 30 s statement timeout | Add a LIMIT, narrow the filter, or pre-aggregate. |
SQL_QUERY_EXECUTION_FAILED | Database rejected the SQL | Re-run with --json to read the full payload. |
SQL_QUERY_CONNECTION_FAILED | Could not reach the database | Service may be restarting — retry shortly. |
SQL_QUERY_SCHEMA_UNAVAILABLE | Schema introspection failed | Service may be unhealthy — check status and retry. |
SQL_QUERY_MULTI_STATEMENT | More than one statement in the body | Send statements one at a time. |
SQL_QUERY_CONCURRENCY_EXCEEDED | Three queries already in flight on this service | Wait for one to finish, or cancel it, then retry. |
Use it from the dashboard
The same surface lives on every PostgreSQL and MySQL service detail page under the SQL Query tab: a CodeMirror editor, a virtualised result grid, a schema browser on the side, and locally-persisted draft + history. Both the dashboard and the CLI talk to the same backend endpoints, so a query you ran from the CLI is subject to the same limits and audit trail (catalog.sql_query and catalog.sql_schema).
Related
- Service Catalog overview
guara catalog deploy— provision a database service before querying it.- Authentication & API keys — the CLI uses the same
X-API-Keyflow as every other command.