Skip to main content
NikoFischer.com

Main navigation

  • Home
  • About
    • My Reading List
    • Recommended Youtube Channels
    • Life Rules
    • Podcast
  • 50-Day Challenge
  • Impressum
Sprachumschalter
  • English

Breadcrumb

  1. Home

Supabase: How to query users table?

🎸
🚀 Beta Running

PYNGUP: Rebellion against toxic productivity

Beta limited to 100 spots. Tasks become social commitments instead of lonely to-dos.

🚀 Join Beta 📖 Read Story "€487 wasted"
Supabase: use sql editor to create a database trigger

Ever wondered how to query your users table in Supabase? This was my questioned of the day: I developed a Node.js middleware for my Vue Time Tracking App that I hopefully can release soon. The exact question was: "how to query users by email?".

Supabase is an open-source alternative to Firebase with PostgreSQL as its database foundation, making it ideal for complex queries.

But from the beginning: I have Projects in my time tracking app. Users can add other users to a project in order to collaborate with them. When adding a user to a project - which by the way is done with the users email address - the app has to determine wether the user already exists or not. If it exists, thats great: then just add the user to the project and send a little notification via mail. If the user does not yet exist, create an entry on the invitation table and also notify the user by email (but with a different transaction mail template).

As I don't want to have this bunch of code and logic in the frontend, I created a little Node.js app in combination with express.js to provide an REST endpoint. My idea was to just listen to this endpoint for incoming invitation requests and query the users table for the given email address using the Supabase JavaScript library.

const { createClient,   } = require('@supabase/supabase-js')
const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_KEY)
supabase
  .from('users')
  .select('id')
  .eq('email', 'doe@example.com')
  .then(response => {
    console.log(response)
  })

But I ended up getting this error:

relation "public.users" does not exist

If you later want to switch to Supabase Edge Functions, check out our guide on CORS configuration in Edge Functions.

It's not possible to query the auth users table directly

As I realized, it's not possible to query the internal auth users table directly. Instead you have to create a copy of it with all relevant data you want to user later on. You can also add other fields to store more user profile data like "first name", "last name", "birth date", "address", etc.

As the only thing I want to do is querying the existing users I just created a small user table. You can do so my using the Supabase SQL Editor. Just select "SQL" in the main menu and click "New query". This opens up a tiny editor window where you can type the following query:

-- USERS
create table public.users (
  id uuid not null primary key, -- UUID from auth.users
  email text
  first_name text,
  last_name text
);
comment on table public.users is 'Profile data for each user.';
comment on column public.users.id is 'References the internal Supabase Auth user.';

This creates a new public table "users" with an id field referencing the auth.users UUID. I also added a field for the email address that I want to query and fields for the first and the last name what I'm going to use for the user profiles.

Important: After creating the table, you should configure Row-Level Security (RLS) to protect your data.

Triggers: Automatically create an entry on the users table when a  new user is created

Now comes the trick: you (or your app) does not have to fill in the entries in the new public.users table. Instead you can use a trigger to automatically do the job for you whenever a new user is created. Or exactly: whenever a new user entry on the auth.users table is created.

Keep in mind: we created a public.users table. This has nothing to do with the auth.users table which is an internal database that handles the authentication process for your app users to access the Supabase API.

To enable the trigger just visit the SQL editor again and type:

create or replace function public.handle_new_user() 
returns trigger as $$
begin
  insert into public.users (id, email)
  values (new.id, new.email);
  return new;
end;
$$ language plpgsql security definer;

create trigger on_auth_user_created
  after insert on auth.users
  for each row execute procedure public.handle_new_user();

Just klick the "RUN" button on the bottom right corner of the editor. Thats it!

Now every time you create a new user or a user signs up to your app the trigger runs and creates a new entry with the users id (UUID) and it's email address in the public.users table.

And now you can query the public.users table for the users email address.

Related Supabase Tutorials

  • Supabase vs. Firebase - Choosing the Right Backend
  • Fix Row-Level Security Policy Errors in Supabase
  • Supabase Edge Functions CORS Configuration

Tags

  • Supabase
  • Node.js
  • Express.js
  • Add new comment

Comments10

About text formats

Restricted HTML

  • Allowed HTML tags: <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.

iancarr1412@li… (not verified)

1 year 4 months ago

Supabase Users

Very helpful article!

  • Reply
Profile picture for user Niko

Niko

1 year 4 months ago

In reply to Supabase Users by iancarr1412@li… (not verified)

Thank you very much for your…

Thank you very much for your feedback 🙏

  • Reply

hello (not verified)

1 year 3 months ago

Setting multiple fields

Is there a way to set the first_name too based on the email?

Like: SUBSTRING(new.email, 0, charindex('@', new.email)));?
im not getting this to work 🤔

  • Reply

Alamin (not verified)

1 year 2 months ago

Is this secure?

I also need to create a table like that for a chatapp. So that I can search the users based on full name and username and also will email. But Is this secure? I mean someone who is a authenticated user (or if it's accessable with anon key) can query and get all the data of all users with a little bit of tricks. Isn't it?

By the way, if you don't want to take the hassle of creating a trigger then you can create a View instead of a solid table. A view is looking at the columns and rows of a table live. So if the referenced table changes, the View data will also be updated.

  • Reply

mohamed (not verified)

1 year 2 months ago

user.user_metadata

how can i get data from user.user_metadata to use it created users table in this query

  • Reply

charles (not verified)

1 year ago

Error in first query

Hey, you are missing an "," after `email text`

:)

  • Reply

Thallyson Dias (not verified)

11 months 2 weeks ago

Nice tip! Thanks

Nice tip! Thanks

  • Reply

Unclebigbay (not verified)

7 months 2 weeks ago

Thanks this solves my issue…

Thanks this solves my issue in 2025!!!!

  • Reply

Jordan (not verified)

7 months 2 weeks ago

just added cascade delete

I added this :

create table public.users (
id uuid not null references auth.users on delete cascade, -- <= this here
email text,
first_name text,
last_name text,

primary key (id)
);

alter table public.users enable row level security; -- <= and this

  • Reply

Sujay Kundu (not verified)

4 months 1 week ago

Thanks very Helpful

For anyone looking to update first_name, last_name etc. You have to update the trigger function.

create or replace function public.handle_new_user()
returns trigger as $$
begin
insert into public.users (id, email, first_name, last_name, age)
values (
new.id,
new.email,
new.raw_user_meta_data->>'first_name',
new.raw_user_meta_data->>'last_name',
(new.raw_user_meta_data->>'age')::integer
);
return new;
end;
$$ language plpgsql security definer;

Here is a blog article if you need more info - https://sujaykundu.com/articles/setup-supabase-for-nextjs

  • Reply

Related articles

Supabase throws "new row violates row-level security policy for table" even though I had created a row level policy for inserts
Supabase vs. Firebase - Unveiling the Differences
Supabase Edge Functions CORS Error Fix - Complete Guide 2025
Supabase Storage: How to Implement File Upload Properly
Building a ChatGPT Clone with Supabase Edge Functions and OpenAI

About the author

Nikolai Fischer is the founder of Kommune3 (since 2007) and a leading expert in Drupal development and tech entrepreneurship. With 17+ years of experience, he has led hundreds of projects and achieved #1 on Hacker News. As host of the "Kommit mich" podcast and founder of skillution, he combines technical expertise with entrepreneurial thinking. His articles about Supabase, modern web development, and systematic problem-solving have influenced thousands of developers worldwide.

Ihre Anmeldung konnte nicht gespeichert werden. Bitte versuchen Sie es erneut.
Ihre Anmeldung war erfolgreich.

Newsletter

Join a growing community of friendly readers. From time to time I share my thoughts about rational thinking, productivity and life.

Nikolai Fischer

✌ Hi, I'm Niko
Entrepreneur, developer & podcaster

Contact me:

  • E-Mail
  • Phone
  • LinkedIn

My Reading List

  • Algorithmic Trading - Ernie Chan
  • Let Me Tell You a Story: Tales Along the Road to Happiness - Jorge Bucay
  • Mindset: The New Psychology of Success - Carol S. Dweck
  • Deep Work: Rules for Focused Success in a Distracted World - Cal Newport
  • The Café on the Edge of the World: A Story About the Meaning of Life - John Strelecky
more
RSS feed