Never use SELECT * in production code. SELECT * fetches every column including large text/blob fields you don't need, wastes bandwidth, breaks when columns are added, and prevents the database from using covering indexes.
SELECT * fetches all columns from the table, including large text, JSON, and binary columns that your code may never read. This wastes database I/O, network bandwidth, and application memory. Worse, it creates a hidden coupling: when a new column is added to the table, every SELECT * query silently fetches it, potentially breaking serialization or exposing sensitive data.
BeforeMerge scans your pull requests against this rule and 4+ others. Get actionable feedback before code ships.
SELECT * seems convenient, but it creates multiple problems:
Bandwidth waste: if the table has a content column with 10KB of text, every query fetches it even if you only need id and title. For 1,000 rows, that's 10MB of data you don't use.
Covering index prevention: a covering index contains all the columns a query needs, allowing the database to answer the query from the index alone without reading the table. SELECT * can never use a covering index because it requests all columns.
Schema coupling: when a column is added to the table, every SELECT * silently includes it. If the new column contains sensitive data (SSN, API keys), it leaks through existing queries. If it's large, it degrades performance of existing queries.
Ambiguity in JOINs: when joining tables, SELECT * can produce duplicate column names, making code fragile and results confusing.
Always specify the columns you need: SELECT id, name, email FROM users instead of SELECT * FROM users. In ORMs, use the equivalent select/projection method.
-- BAD: fetches every column including large ones you don't need
SELECT * FROM articles
WHERE published = true
ORDER BY created_at DESC
LIMIT 20;// BAD: Supabase equivalent
const { data } = await supabase
.from("articles")
.select("*")
.eq("published", true)
.order("created_at", { ascending: false })
.limit(20);-- GOOD: only the columns needed for the list view
SELECT id, title, excerpt, author_id, created_at
FROM articles
WHERE published = true
ORDER BY created_at DESC
LIMIT 20;// GOOD: Supabase equivalent
const { data } = await supabase
.from("articles")
.select("id, title, excerpt, author_id, created_at")
.eq("published", true)
.order("created_at", { ascending: false })
.limit(20);Search for SELECT * in your codebase:
grep -rn "SELECT \*\|select("\*")" --include="*.ts" --include="*.sql" src/* with an explicit column list.select("*") with .select("col1, col2, col3")