camelCase table or column names not working
Postgres folds unquoted names to lower case, so a table called mealPlans or a column called createdAt breaks in SQL. Quote them, or rename them to snake_case safely.
What you see
A table or column you can see in Studio's table editor "doesn't exist" in SQL:
ERROR: 42P01: relation "mealplans" does not exist
LINE 1: select * from mealPlans
ERROR: 42703: column "createdat" does not exist
HINT: Perhaps you meant to reference the column "mealPlans.createdAt".
Notice that the name in the error is all lower case, even though you typed mealPlans.
Why it happens
Postgres folds unquoted identifiers to lower case. select * from mealPlans is read as select * from mealplans. Only a name in double quotes keeps its case, so a table created as "mealPlans" (which is what happens when you type a camelCase name in a table editor) can only be reached as "mealPlans" from then on.
supabase-js usually hides this, because the Data API quotes every name you pass. supabase.from('mealPlans').select('createdAt') works fine. The trouble starts in raw SQL: RLS policies, database functions, triggers, views, migrations and ORMs that don't quote.
How to fix it
You have two options.
Option 1: quote the names everywhere in SQL.
select "id", "createdAt"
from public."mealPlans"
where "ownerId" = (select auth.uid());
This works, but every policy, function and ad-hoc query needs the quotes, and forgetting one gives the error again.
Option 2 (recommended): rename to snake_case once.
Rename the table and its columns:
alter table public."mealPlans" rename to meal_plans; alter table public.meal_plans rename column "createdAt" to created_at; alter table public.meal_plans rename column "ownerId" to owner_id;Renames are instant and don't rewrite data. Policies, indexes, foreign keys and triggers follow the rename automatically. Function bodies don't: they store their SQL as text, so update any function that mentions the old names.
Find functions that still use the old names:
select p.oid::regprocedure from pg_proc p join pg_namespace n on n.oid = p.pronamespace where n.nspname = 'public' and p.prosrc ilike '%mealPlans%';Update your app. Change
.from('mealPlans')to.from('meal_plans')and regenerate your TypeScript types.If old app versions are still in use, keep a temporary view with the old name so they keep working while you roll out:
create view public."mealPlans" with (security_invoker = true) as select id, created_at as "createdAt", owner_id as "ownerId" from public.meal_plans;security_invokermakes the view apply the table's RLS policies to the caller. Drop the view once every client is updated.If the Data API still reports the old names, reload its schema cache:
notify pgrst, 'reload schema';
Going forward, use lower-case snake_case names for tables and columns. If you want camelCase in your JavaScript objects, rename in the query: select('id, createdAt:created_at').
On SupaHost
- Run renames in Studio's SQL editor (Dashboard → your project → Database tab → Open Studio) or with MCP
apply_migration, so the change is recorded in your migration history. - MCP
generate_typescript_typesgives you the new types after the rename.