5.0 KiB
npx -y @insforge/cli db query
Execute a raw SQL query against the project database for targeted inspection and row-level data changes.
Syntax
npx -y @insforge/cli db query <sql> [options]
Options
| Option | Description |
|---|---|
--json |
Return rows as JSON for scripting |
Examples
# Basic query
npx -y @insforge/cli db query "SELECT * FROM posts LIMIT 10"
# Update rows
npx -y @insforge/cli db query "UPDATE posts SET status = 'published' WHERE id = 'post_123'"
# Insert rows
npx -y @insforge/cli db query "INSERT INTO posts (title, status) VALUES ('Hello', 'draft')"
# Delete rows
npx -y @insforge/cli db query "DELETE FROM posts WHERE archived = true"
# Inspect Postgres system catalog
npx -y @insforge/cli db query "SELECT table_schema, table_name FROM information_schema.tables WHERE table_schema = 'public'"
# Inspect InsForge-managed schema data
npx -y @insforge/cli db query "SELECT * FROM auth.users LIMIT 10"
# JSON output for scripting
npx -y @insforge/cli db query "SELECT count(*) FROM posts" --json
Output
- Human: Formatted table
- JSON:
{ "rows": [...] }
Restrictions
- Do not include transaction control statements in the SQL.
db queryrejectsBEGIN,COMMIT,ROLLBACK, andSAVEPOINTwith the errorTransaction control statements are not allowed.- Each
db querycall already runs as a single statement in its own transaction, so an explicitBEGIN ... ROLLBACKblock is not needed for atomicity.
Rollback Rehearsal (Dry Run) Pattern
To rehearse a guarded data change without committing it, run one DO block that performs the mutation, validates the result, and ends with RAISE EXCEPTION so PostgreSQL rolls the whole statement back:
npx -y @insforge/cli db query "DO \$\$
DECLARE
updated_count integer;
BEGIN
UPDATE posts SET status = 'draft' WHERE status IS NULL;
GET DIAGNOSTICS updated_count = ROW_COUNT;
IF updated_count > 100 THEN
RAISE EXCEPTION 'guard failed: % rows matched, expected at most 100', updated_count;
END IF;
-- Validation passed; raise anyway so the statement rolls back
RAISE EXCEPTION 'rehearsal ok: % rows would be updated (rolled back)', updated_count;
END
\$\$"
The BEGIN inside the DO block is the PL/pgSQL block keyword, not a transaction statement, so it is allowed.
A rehearsal always ends as a failed command. Rolling back means raising, so the command writes to stderr and exits non-zero (1) on both the pass and the fail path — that is the expected outcome, not a broken query. Read the message to tell them apart:
| Output on stderr | Meaning |
|---|---|
Error: rehearsal ok: 42 rows would be updated (rolled back) |
Validation passed; safe to apply |
Error: guard failed: 250 rows matched, expected at most 100 |
Validation failed; do not apply |
Under --json the same text arrives on stderr as {"error": "rehearsal ok: ...", "code": "INTERNAL_ERROR"}. Do not treat the non-zero exit code as a reason to retry.
Once the rehearsal reports rehearsal ok:, rerun the mutation as a plain db query statement to apply it.
Permission Model and Schema Changes
db query runs as project_admin.
public: full access for normal data changes and schema work.- Postgres system catalogs such as
pg_catalogandinformation_schema: read-only inspection is allowed. - InsForge-managed/system schemas such as
auth,storage,realtime,payments,graphql,extensions,pg_catalog,information_schema, orsystem: do not write or run DDL unless you are working on that specific feature module and its docs explicitly allow the operation.
Use npx -y @insforge/cli db migrations new ... and npx -y @insforge/cli db migrations up ... for schema changes on public application objects.
Use db query for:
- reading app data and inspecting managed-schema data
- inspecting Postgres system catalogs such as
pg_catalogandinformation_schema - backfilling or correcting rows in
public - one-off row updates in
public
For schema, RLS, grants, triggers, functions, indexes, and extensions, create a migration and apply it.
InsForge SQL References
When writing SQL for InsForge, use these built-in references:
| Reference | Description |
|---|---|
auth.uid() |
Returns current authenticated user's UUID (use in RLS policies) |
auth.users(id) |
Built-in users table — use for foreign keys, not a custom table |
system.update_updated_at() |
Built-in trigger function that auto-updates updated_at columns |
Complete Example: Row-Level Data Fix
# Inspect the current rows
npx -y @insforge/cli db query "SELECT id, status FROM posts WHERE status IS NULL"
# Backfill missing row values
npx -y @insforge/cli db query "UPDATE posts SET status = 'draft' WHERE status IS NULL"
Notes
- For schema changes and RLS policy changes, use the migrations workflow in migrations.md.
- For advanced access-control patterns (RLS recursion prevention, SECURITY DEFINER, performance), see access-control.md.