winsoroaks
winsoroaks8mo ago

when is the best time to create a user entry in the db?

hi all! im curious what's the best practice here. assume that i have a to-do list app and using clerk for auth. if i allow the user to sign in via google, there's no clear way to do "user has signed up" -> "i need to register user in db."
when should i create an entry of the user in the db? im thinking of when the user has created a to-do list and clicked on the save button, i can check if the user has existed in the users db and create the entry. is this reasonable? thank you
18 Replies
Matt Luo
Matt Luo8mo ago
That seems reasonable. I feel like this is not a Convex-specific question: You'll have to consider your own circumstances. Clerk charges per active user, so you'll need to consider your revenue per Clerk user. For a to-do app, you may want to delay creating a user account in Clerk for as long as possible: - Perhaps add your settings page to your publicRoutes in middleware.ts. - Enable anonymous accounts if possible. I don't think this is a native feature of Clerk, though. I am thinking something like this: https://firebase.google.com/docs/auth/web/anonymous-auth So, I think you would need to use the <Authenticated>, <Unauthenticated>, <AuthLoading> components a lot In this Discord server, some Convex staff have made some informal comments about building a native lightweight auth. It's not clear to me whether a native auth solution would be net-positive to Convex Inc.. But it would be interesting if developers had a way to very affordably create user accounts, but have - those user accounts work alongside full-blown Clerk accounts. - a path to converting them to Clerk user accounts
winsoroaks
winsoroaksOP8mo ago
ooof good point... damn i should write a cron to kick users who are inactive for 30 days 😛
Matt Luo
Matt Luo8mo ago
Clerk only charges per active user
winsoroaks
winsoroaksOP8mo ago
awesome! i guess that's fine then. what are you u using for ur auth? is it clerk too?
Matt Luo
Matt Luo8mo ago
I am using Clerk But i have experience with Okta, Firebase, and Appian auth This blog post is from Feb 2023, but still relevant: https://blog.hyperknot.com/p/comparing-auth-providers I think with a B2C product with low revenue per user, you will run into this issue with any auth vendor I think part of why Supabase got famous is their affordable auth. This blog says "Supabase Auth is the gateway drug to the platform." But the Supabase CEO in interviews says the auth team is "always busy" And auth is a easy way for disgruntled people on the internet to criticize the platform in a low-effort way I think Clerk is the optimal path for now, all things considered If you are building a to-do app for your own learning purposes and not as a business, then you should definitely use Clerk. Clerk will teach you what good looks like and slowly introduce you to OAuth concepts over time earlier in my career, mid-2010's, I manually built OAuth integrations for LinkedIn and Facebook. Made a claim for a token and stored it in my own database. It was hard. I had to learn each sub-concept from fresh. Very tedious
erquhart
erquhart8mo ago
This has come up a few times and I haven't seen a canonical approach. I use Clerk, and run an upsert every time a user authenticates. I also update user info from Clerk in the same function, rather than using Clerk's webhooks (for now).
useEffect(() => {
if (isAuthenticated) {
;(async () => {
const user = await updateUser()
setSentryUser(user.clerkId)
})()
}
}, [isAuthenticated])
useEffect(() => {
if (isAuthenticated) {
;(async () => {
const user = await updateUser()
setSentryUser(user.clerkId)
})()
}
}, [isAuthenticated])
Matt Luo
Matt Luo8mo ago
@erquhart - So are you saying that every time you execute an upsert on a table with a foreign key to users, you are running updateUser()?
erquhart
erquhart8mo ago
No, every time a user authenticates to my app, I call updateUser(), which runs an upsert underneath, inserting the new user or updating the user's data (if there's a delta between their clerk info and the info in the convex db). (Or maybe "yes" if we're saying the same thing? 😄)
Matt Luo
Matt Luo8mo ago
I think I understand. You are executing the updateUser() every time the user makes a sign-in.
erquhart
erquhart8mo ago
It's lazy lol, but it works (It also covers initial sign up without any special logic)
winsoroaks
winsoroaksOP8mo ago
thank you erquhart sir. sounds like this is the best way to do it yea i agree. but i dont wanna spend time doing auth. and clerk is easy to setup 😅
erquhart
erquhart8mo ago
Yeah, at least for getting going. Go back and firm up once the thing makes some money lol
Matt Luo
Matt Luo8mo ago
I forgot: clerk has first day free pricing First Day Free means no charges for users who sign-up but never return. Users are only counted as active when they come back after 24 hours. So, no strong need to put a lot of effort into delaying the user account creation
winsoroaks
winsoroaksOP8mo ago
I think im definitely day 1 creating user. Just thinking whats the best way to register them in my convex users table, 😅
Michal Srb
Michal Srb8mo ago
Relevant docs: https://docs.convex.dev/auth/database-auth Better documentation for webhooks will be released next week.
Storing Users in the Convex Database | Convex Developer Hub
You might want to store user information directly in your Convex database, for
winsoroaks
winsoroaksOP8mo ago
Oh is this what i needed! Thank you!! quick follow up: what's the best way to send an email to the user who just signed up? since sending an email using resend requires me to use an action and createUser is a mutation, does it mean i need to use an action to "wrap" the createUser mutation and sendEmail action?
sshader
sshader8mo ago
Sounds like you want to schedule the action to send an email from the mutation that creates the user (e.g. ctx.scheduler.runAfter(0, internal.users.sendEmail, ...)) These docs (https://docs.convex.dev/functions/actions#calling-actions-from-clients, https://docs.convex.dev/zen) touch on this, but wrapping the whole thing in an action (vs. scheduling) is generally an anti-pattern since it means you lose out on a lot of the benefits of a mutation (e.g. they're guaranteed to run exactly once)
Actions | Convex Developer Hub
Actions can call third party services to do things such as processing a payment
winsoroaks
winsoroaksOP8mo ago
ahhh thank you. totally forgot bout the scheduler 🤦‍♂️

Did you find this page helpful?