Don't connect as the superuser
The default postgres user is the superuser — bypasses all permission checks, can drop the database. Production applications must connect as a least-privileged role with only the privileges they need: usually SELECT, INSERT, UPDATE, DELETE on the application tables, nothing more.
Roles and grants
Create an application role (app) and grant it the specific privileges. Use GRANT USAGE ON SCHEMA + GRANT SELECT, INSERT ON TABLE. ALTER DEFAULT PRIVILEGES automatically grants the same privileges on tables you create later.
Row-Level Security
RLS lets you push multi-tenant rules into the database itself: "doctors only see their own patients," "users only see their own posts." A policy is attached to a table; every query against that table has the policy applied transparently. Supabase's auth story is built almost entirely on RLS.
SQL injection — solved problem
Parameterised queries (driver-level) make injection structurally impossible. Use them everywhere. Never concatenate user input into SQL. Never trust client-supplied identifier names; if you must dynamically pick a column, validate against an allowlist and use quote_ident.