skip to content

Build an App With Supabase and NextJS

Supabase combines database storage and authentication into a powerful workflow for web devs. In this episode, Jon Meyers will teach us how to build a Next.js app with Supabase and deploy it to Netlify!

Full Transcript

Click to toggle the visibility of the transcript

Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

JASON: Hello, everyone. And welcome to another episode of Learn with Jason! Today on the show we have Jon Meyers. How are you doing, Jon?

JON: I'm doing excellently, how are you going, Jason?

JASON: I'm doing well, I would be doing better if Chris wasn't in here trying to get me to buy expensive camera gear. I don't know if you see the comment, full frame cinema camera. Some people's kids, man. They're always trying to get me to spend my money on toys and it works. It's frustrating.

JON: Amazing what you can buy with money. Always seems to be something to tweak in the office for sure.

JASON: Welcome, all. It's been a minute. We are doing an odd time. I'm super-stoked, though. And welcome Alastair Young, first time chatter. What up? So, Jon, I feel like I have been following you for a long time. This is actually our first time meeting in-person. Or, you know, in-person. But for folks who aren't familiar with you and your work, do you want to give us a little bit of a background on yourself?

JON: Yeah, sure. So, I have been a software developer for maybe 5 or so years. I did -- when I was in university, did a little bit of teaching alongside studying. Which I found really fun. And so, when I finished university, I started teaching at a bootcamp here in Melbourne, Australia. And that was really fun. But I felt like I wasn't really getting the kind of challenges that come along with building something that someone else wants you to build. Building someone else's crazy idea. I was a software engineer for a real estate company here in Australia and then a bank in Australia. And I felt I got all the insight I needed in software engineering and I was really missing that teaching aspect. And so, joined Supabase as a developer advocate. And now I get to create fun demo projects and go on cool fun streams like this and hang out with fun people.

JASON: I love it. And I'm super-excided. you're based in Australia, which is why we're streaming at a different time today.

JON: Yeah, sorry about that.

JASON: It is 4 p.m. in Portland right now. But it is what time for you?

JON: 11 a.m. So, very, very reasonable for me.

JASON: But 11 a.m. in the future because you're on January 12th, right?

JON: That's true. I can tell you, nothing really exciting happens between January 11th and 12th. You'll be okay.

JASON: I will say, an unexpected benefit, seeing people in the chat, E-bay, Diggette, welcome, thanks for the cheers, Dthompson. This is an exciting one for me because you and I talked about doing a Supabase episode a while ago, but due to schedules and the holidays and all those things, I told myself, I'm not going to try Supabase until we do this episode because I want to make sure that I get the full experience of like first time user. But then it got delayed so much, it looks like I'm intentionally not using Supabase for my own reasons. That's absolutely not the case. I'm really excited. I just wanted to give this a try. Before we actually start coding, though, I want to talk a little bit more about more of the abstract here. Because Supabase is unique -- or if not unique, it is -- it is kind of positioned interestingly comparative -- compared to some of the other databases out there because I think when I call it a database, I'm not even being completely accurate, right?

JON: Yeah, part of it is.

JASON: Give us the elevator pitch. What is Supabase and what makes it kind of unique? What makes it stand out from the other places in the field?

JON: Sure. And so, originally our positioning was that we were a -- an open source alternative to Firebase. And so, we -- a bunch of people at Supabase have -- have used Firebase extensively and just love that developer experience. Like it's such a great product. And as a developer trying to just get up and running with somewhere to store stuff and some authentication, authorization, some real-time stuff. All of that. It just it makes so incredibly easy. The problem that a couple of people, the two founders of Supabase found, was once you tried to take that to scale, sometimes you may hit some limitations that -- that something like a relational database can solve. And, initially, we positioned ourselves as the open source alternative to Firebase. And, trying to kind of build feature parity, at least some of the core products that exist within Firebase. But offering it in a relational database world which kind of unlocks some other opportunities.

JASON: Interesting. Okay.

JON: Now, it's more like -- we're sort of -- I think maybe we still have that tagline on the website. But we're sort of moving away from it a little bit and just being a collection of tools that wrap around a postgres database and really just try to kind of surface all of the --

JASON: Got it.

JON: Cool stuff that postgres gives you out of the box that a lot of people aren't aware of just because sometimes learning SQL is a little bit daunting and a little bit sometimes some of the resources are a little bit antiquated and it doesn't seem as fun as some of the new, shiny things.

JASON: For sure, yeah.

JON: Supabase is one of the new shiny things.

JASON: And hey, we're in frontend Dev, we love new shiny things. I'm interested, though, because I -- I wasn't expecting you to tell me that it was postgres under the hood. It -- because I've heard that, it's the open source alternative to Firebase, I was expecting more of like a Mongo, like a document store versus a relational database. So, that's really interesting to me. Does that mean, like, so, Supabase is an open-source tool. So, does that mean that I can get any postgres database that I have and I can stand up Supabase on top of it? Or is it -- are they kind of linked like that?

JON: Yeah. So, we -- you can install your own local instance of the entire Supabase stack. So, we've open sourced all of the different pieces so you can grab just auth or you can grab just real-time.

JASON: Interesting.

JON: Or you can -- we've just recently open sourced the dashboard so you can use the dashboard standalone with your own postgres instance that you want to host anywhere. But what we also offer is a hosted environment where you can just create an account. That's what we'll be looking at today. Create an account and really easily get up and running with a postgres instance that's all been configured for you with auth, databases, real-time and authorization kind of ready to go out of the box.

JASON: Got it. Got it, got it. Okay. That's really cool. So, maybe one thing that would be worth talking about here is just the... sometimes when you see a tool talk about like I'm gonna do everything, you fall into a little bit of a like -- well, we do everything, but not very well. And judging by the chatter that I've heard on Twitter, that doesn't seem to be the case with fire -- or with Supabase. I'm not gonna be able to stop doing that today. I'm so sorry to everyone.

JON: That's fine.

JASON: But with Supabase, it seems like people really like the way that these are blended together. So, what do you think is the secret sauce there? Like what makes that work well together versus feeling like kind of disjointed pieces that are bolted together at varying levels?

JON: Yeah. I think this is why we kind of shifted our focus a little bit. Because initially we were trying to just I think build too much. We were trying to solve all of the problems that Firebase solves. And then when we realized we were kind of starting to -- to grow -- or starting to focus on things when the kind of core offering probably needed a little bit more of our attention, that's when we started really focusing on this integration between those different services. And, today we'll be looking at implementing auth and a hosted database. And then we'll see how easy it is to then tie that into our authorization rules which we're also gonna write in the database. But because we're doing all of those things within this kind of Supabase ecosystem, because we authenticate with Supabase and then our data is stored with Supabase, it means that we can do some really powerful things because it inside our SQL, we can know who the user is that's requesting that data. And, that kind of really tight integration between those things is I think what -- what Supabase offers and what we definitely want to keep focusing on. Is every time we release something, it's like how does that fit into the rest of this kind of environment or this model where everything's interconnected and can talk to its -- talk to each other.

JASON: Sure. Yeah. And that is kind of an interesting way to look at it because I think, you know, the trick is that I think everybody needs to solve a set of problems. And everybody's unique set of problems is always a little bit different. But inside that unique set of problems are a huge number of heavily overlapping pieces. You know? Almost every app is gonna have to have a way to have somebody sign in. You're almost always gonna have to have a way to have permissions management. You usually as an app gets more complex need to have a way to have more granular controls. You have authors versus editors versus admins. And all of those things -- they're not that different, right? At the end of the day, you just need to be able to say, you're an admin. You can do whatever you want. You're an editor, you can edit anybody's post, but not delete them. You're an author, you can work on your own stuff. You're a commenter. You can have your own opinions. That doesn't change much from app-to-app. As a developer, usually what I get stuck on is when I have a build something that already exists and I can feel the gap between my ability to implement it extremely well and what I know is possible by looking at well-developed systems. If I log into Google Docs or systems that have done this well like Sanity or something where they've got great presence APIs. I can see people in there. And then I'm trying to roll my own, I guess I can put a hash password in a database and maybe attach that to a user -- I don't know how that works. I'm kind of caught in this trap because I can't build the thing that I know should exist because it's not my area of expertise. This is before I build the app. I'm mired down in the frustration of trying to build boilerplate. what I find exciting about tools like Supabase and others in the ecosystem is it feels like what's happening is more and more of the stuff that's the same for 95% of apps is turned into highly-focused and extremely easy-to-use services. And I just get to say, ah. That piece is done. Like, here's my credit card. I am finished thinking about this forever.

JON: Yeah. And you won't even have to give us your credit card that early.

JASON: Yeah, yeah.

JON: The free tier is very, very generous. Yeah. That's exactly the point. Give you the tools that you need to accomplish what every application needs. A lot of applications needs. Authentication, authorization, data store stuff. And give you a click of the buttons and focus on the product that's unique and what you want to build.

JASON: We're talking about authentication and the data storage. And correct me if I'm wrong, but the other piece we touched on but didn't dig into is realtime. And having real-time features is very nice. It's very cool when I don't have to reload the page to see new comments come in or a like button tick up or to see new posts come on to the page. And Supabase has that baked in from the get-go, right?

JON: Yeah, that's right. And so, you can enable real-time on any of your tables and then you can subscribe to the different kind of events that happen in the database. We give you that kind of granular control where you can subscribe directly to just like insert event. So, something like comments. You might just care about new comments that are coming in. Or maybe subscribe to insert and update comments as someone changes it and you're live on the page, you see it updated. And so, yep. Supabase gives you that kind of granular control to subscribe to particular -- particular tables. So, if you only care about the comments that are coming in on a post, you don't care about -- like if you're focused on one post, you don't care about an author authoring another post somewhere else. You can't see that on your page. You only care about the comments that are being written for that particular post that you're looking at. And what I was talking about before with all of these different pieces kind of being integrated into this Supabase environment is that we now have just recently late last year we launched an update to real-time which now makes it adhere to those authorization rules that we were talking about. And so, you don't need to think about from when you're subscribing to event like should this person actually know that this thing changed in the database? Because it enforces those authorization rules. They'll only see the things that -- that they're meant to see. The things that you --

JASON: That's -- that's really cool. I mean, that's really nice. So, this is the sort of stuff that, you know, I have been building apps for a long time and I remember back in, you know, it was earlier 2000s or mid-2000s I was trying to build out basic CMSs for clients. I was running an agency at the time. And I always wanted to have that type of functionality where I could say, like, say, you got a draft submitted by one of your freelancers. I want to just send you an email or something like that. And I kept finding myself in these scenarios where I would see something I wanted to exist and I would look around. And all I could find is somebody had roughly documented sort of how it worked in another system. Oh, no, I got to go build this stuff myself. I never did. I would always get a prototype, and it would never work very well and I would get overwhelmed and I would quit. what I find exciting is how much of an expert do I need to be in real-time or data administration or any of these things what were really the blockers for me? I didn't have the background expertise, I wasn't a database architect. I didn't have true real-time understanding. Like how much do I need to know to use a tool like Supabase?

JON: Yeah, very, very little. And that's kind of the point of kind of enabling all the cool things that postgres gives you but in a much nicer, easier, less-scary way. And so, a lot of Supabase you can just click around the UI and really achieve some pretty complex things. And, yeah. You don't need to be like a DBA just to be able to build your application. You can very quickly create this quite complex kind of backend and then just focus on what you want to build for your actual product.

JASON: I love that. I'll tell you what, Jon, if there's one thing that I'm very good at, it's knowing very little. I am -- I'm ready. I'm ready. Okay. So, I think that feels like a pretty solid overview. It -- I get the sense that Supabase is suitable for beginners. Would you agree?

JON: Yeah, definitely.

JASON: If you're capable of building a frontend, you can plug into Supabase and start building some things

JON: Sure.

JASON: Is there anything else that somebody who is cautious about getting into databases, real-time, authentication, anything you want to assure them about -- or I guess just anything you want them to know if they're either being intimidated by it or feeling like maybe it's not for them?

JON: Yeah. Well, I think something that is really unique about Supabase is because it is just wrapping around a postgres database, like it's a collection of tools that make it really easy to get up and running with that postgres instance. But then that postgres instance is just postgres. You could use any other tools with that. You could use Prisma if you prefer to use Prisma to run migrations and things like that. It's really, really simple to just connect to the Supabase postgres instance using your connection string. If you want to take it completely outside of the Supabase ecosystem, you can just do a dump of your entire database and just put that somewhere else. And so, yeah. I think that kind of portability is something that you definitely don't get with some of the other tools in that space.

JASON: No, that's -- and that's interesting, too, because when you think about postgres, I mean, postgres is probably one of the most battle-hardened database tools out there. Like everybody's using postgres. Like if you dig deep enough, everybody's got a postgres database in production at every single scale. And that I think is -- that's a really good sign. I feel like a lot of times when you go to push a new tool, you're like, hey, I found this tool. It's gonna make our lives really easy. And the first question you get is it production-ready? Like what's gonna happen if we become a unicorn and we have hundreds of thousands or millions of users, like is it actually gonna function? And I mean, when you're looking at postgres, it's like, yeah. It's gonna.

JON: Really. And not just if your thing happens to be super-successful. But also if Supabase happens to not be successful at all and entirely fold, it's not trapped in some proprietary system that like you haven't needed to learn a particular flavor of SQL or a particular flavor of a way to do your database administration. You can just take that database, put it anywhere else.

JASON: That's a really good point. There's a -- there's a question about coupling your database schema to client code. Is that baked into Supabase or more of a design decision you can make as you kind of built out your apps? Or do you even think about your DB schema as part of building out apps with Supabase?

JON: So, yeah, it's sort of like a similar architecture to what you would see with a lot of CMSs and a lot of hosted databases. Where your database schema and your, you know, all of your authorization rules and all of though things are in Supabase. But that's a completely separate system from your client application. And so, what we'll be building today will just be a Next.js application that will be using the Supabase client library to talk about to our Supabase instance. But you could just be doing it with like REST, HTTP requests. Or like the Supabase JS library gives us some nice conveniences. But this is just that same kind of architecture that you're used to where you have this API talking to a database. And that's separate from your client application. So, you still write your client application as a completely separate thing. You're just, yeah. All of the kind of databasey-hosted stuff is taken carefully.

JASON: Got it, got it, got it, yeah. And yes, I am very excited to see the Australian and New Zealand crowds showing up tonight. Welcome, everybody. Glad you could make it! I hadn't really considered doing a later show. But, you know, maybe this is something we need to do. Get a little more global time zone-friendly. If you're into that, Tweet at me. Let me know. But okay. So --

JON: I can come on every week, Jason. [ Laughter ]

JASON: I'm ready! I'm ready. So, I think at this point probably makes the most sense to just start looking at this thing in action. So, let's head over and -- and move into our pair programming view and we'll do that. So, everybody hang tight. Here we go. All right. So, we are now -- are you gonna load? What are you doing? Come on, overlay. Hold, please.

JON: I'm seeing --

JASON: Yeah. It's like goofy. It didn't get the data. There it is. All right. There's our data. But okay. So, here we are before we start building things, let's do a quick shoutout to the sponsors and captioning. We have Amanda from White Coat Captioning here with us today doing lye captioning. That is on the home page of the site with learnwithjason.dev. Thank you so much for being here. And Netlify, Fauna and Auth0, making the host more accessible to more people. We're on the hunt for new sponsors in 2022, if your company wants to sponsor a show like Learn with Jason, drop me a little DM, huh? And click on the logos to check these companies out. They are all clickable so you can go learn things. And we're talking to Jon Meyers today. You can go and give him a follow on Twitter. And this is a new handle for you. You just did the shift. I got real confused.

JON: Sorry about that. I broke the Internet when I went and changed my Twitter handle. Didn't realize how many things were pointing to it that I basically spent months regretting the decision.

JASON: Just nothing but regret. I mean, that's a pretty good standard state of being on Twitter, I think. Just constant regret. We're working Supabase. So, over at Supabase.com you can find the details of how that works and all those things. I'm going to skip all the tutorials and docs and instead just make Jon tell me things. We'll talk about that later what we're beginning to build it with. What's the first step? What do I do first?

JON: It sounds like you want to start a project.

JASON: I do indeed want to start a project. And then sign in.

JON: There you go. As you sign in with GitHub and authorize Supabase to have access to everything.

JASON: Just the email. Always love that.

JON: So, we're just using this for authentication. We don't care about your actual GitHub projects or anything. It's just we're using -- I think it's now -- I'm pretty sure this is now using Supabase. I think that was a recent change we made. We were recently using Auth0 and everybody called us out, say you're an auth provider. You can do authentication and authorization for all of these apps, why don't you do it for yours? We have done that now, we now I'm pretty sure are using our own dogfooding everything now.

JASON: Good, good, good.

JON: And everything is Supabase. Now we can click New Project.

JASON: Okay. I have an org. I do not have permission...

JON: Only the organization owner. You just --

JASON: Oh, no.

JON: This might be a really, really short stream, Jason. Maybe just refresh again and see.

JASON: Now I'm the owner. Okay. Let's go to projects. I'm going to create a new project. I'm gonna refresh the page. Hey!

JON: Hey!

JASON: Here we go. Looks like something got out of sync there. All good.

JON: You refreshed. Cool. This can be the name of our project.

JASON: What are we going to build today?

JON: A blog. A nice simple blog with comments just to show off all of those different pieces.

JASON: Got it.

JON: You want this to be a very secure password as this will be used as your postgres database password.

JASON: Let me generate one over here. I'm going a LWJ... okay. Got a password. Is this going to be -- all right. Good?

JON: You've done this before, I see. Now we can --

JASON: Is there an ideal location.

JON: So, this is just sort of I guess the best practice is to try to pick somewhere that's as close to your users as possible. If we're building a demo application, probably just as close to you as we can. And then the pricing plan, if you want to drop that down, change that to the free tier. The free tier will give you two projects. There is a pricing page somewhere that shows you a whole bunch of stuff. But yeah, it's very unlikely that you will hit the top of the free tier. Oh, yeah. Here you go.

JASON: Dedicated data base. That's already really cool. Unlimited API requests, cool. Real-time, very cool. If you get to the point where you need things like database space, optimize instances, automatic backups.

JON: Yep. We give you 500meg of database storage which is a surprising amount of text if you want to put a whole bunch of text. But we also do object storage. That's there.

JASON: Got it.

JON: Which we won't go into today. I think it's a gig or something on the free plan. Nice.

JASON: Yeah. Up to a gigabyte.

JON: Yes, hosted instance and the unlimited API requests are --

JASON: It's big.

JON: Are two things that make it not very likely that you are going to hit that on your project.

JASON: It looks like it created a public key and a secret key.

JON: Yeah. You scroll back up, the little orange text is saying we're going off and creating all of these things. We've got a database instance that's being created for you. It's setting up all of the initial auth stuff, all of the authorization stuff. A realtime server. It's a little bit of infrastructure that we need to scale up. While it's doing that, we can go ahead and create our Next.js application.

JASON: We're going to be using Next.js. I'll let you tell me what I want to do here.

JON: Yes, sure. Let's go NPX, we can run directly from npm. This is the create-next-app package. This is a fun way to get up and running with Next.js. Do you have any preferences for things as in -- oh, yeah, I guess this will step us through it. You can call it whatever you would like.

JASON: Call it a Supabase blog.

JON: Cool.

JASON: And it installed React, React DOM and next.

JON: I think from playing around with the project yesterday, I think the default is now that it uses TypeScript, I think. If you -- let's work it out. Let's go code.

JASON: Let's see. Let's see if I'm gonna have to remember how TypeScript works.

JON: Oh, yea. Nice.

JASON: JavaScript.

JON: Okay. We're good.

JASON: We dodged a bullet.

JON: We're both ready for this now.

JASON: One of these days I'm going to have to actually learn TypeScript so that I can function.

JON: So, we can just get rid of everything in the outside and closing div. Let's just keep a little bit of those nice styles and get rid of all that and just say just working or something. Put something on the page so we can test that it's all, you know, and we haven't broken anything yet.

JASON: All right. So, we've got -- we've got a basic -- basic thing going. I'm gonna run Netlify Dev which I think will just work. Let's make sure that it all does what I want. There we go. Okay.

JON: Very cool. Microsoft? Okay, cool.

JASON: Sorry, I use Edge and I haven't done like the blank tab thing so it gives me the branding when I do that.

JON: Okay.

JASON: Okay.

JON: Okay. So, we have a Next.js application that's working. That's pretty good. So, we probably want to -- well, why don't we check how our Supabase instance is going. Do we have? Is that all finished creating? It is.

JASON: Yep.

JON: It's done creating the things. Yeah. You'll see we have database, auth, we have app storage, a whole bunch of stuff and we have our API keys which we can probably -- yeah. Come back to in a second.

JASON: Okay.

JON: So, on the left you have a whole bunch of different menus and so, different things that we can do. Should we just go through a quick -- a quick step through --

JASON: Let's do a quick tour.

JON: The table editor, yeah, we can start there and actually create some tables if you want. So, let's create a new table and call this one posts, all lower case. Which is recommendation for postgresy things. We're going to leave the activities off, so we can see when we flip it on. But just a little bit of foreshadowing, level security is how we can implement authorization in our Supabase database. We want a title, make this one text.

JASON: Don't need a default value. Primary.

JON: No, but let's take a is_published column. Which can be a Boolean.

JASON: Boolean.

JON: Or bool. In Supabase land.

JASON: Bool, all the way to the bottom. And the default will be false.

JON: Correct. And make a content one as well. So we've got a title that we can display on like our landing page with a list of different blogs.

JASON: Oh, here's a question.

JON: Yep.

JASON: What's the difference between text and varchar?

JON: He's gonna do it to me. Gonna do it to me. Make me explain the database things. Varchar, I don't know the pronunciation. In university it was pronounced to me as Varchar. I don't think it does in the US for Supabase, but it gives you the opportunity to specify how many the maximum characters are the max for that column. You could say Varchar 5, and the length of the thing stored in that field is up to 5 characters.

JASON: Got it.

JON: It used to be important when database storage was expensive and keeping things as small as possible. But now we don't care. We've got all the bandwidth we need and all the storage we need. Supabase's problem. I'm sure there's a maximum to what text it will store. But it's incredibly large and it's just a variable size field.

JASON: Great. Do we need anything else?

JON: No. I think that's all we need for this. Click save and that's going to create that table and then create that columns. And in a moment, we will be able to see our posts. Surely. It's a --

JASON: And they're saying it's short for varying character. Makes sense. Buy that.

JON: Yeah.

JASON: Okay. We have this thing up here. Security is not enabled.

JON: Ignore for it for now. We can add a blog post directly from here. The creator and author out there. Create a title for what we actually want to display. And some content. Perfect. I love it. I love it.

JASON: Should we publish it?

JON: Let's leave it unpublished for now.

JASON: Okay.

JON: Let's leave it as the default value. If the default value is false, you can add false. Either way. Cool. So, we now have a post. And then why don't we add one more post to see the difference between a published and unpublished post. Come up with another joke. On the fly.

JASON: Do it on the fly. Oh, god. I got nothing.

JON: You prepared one. You had one --

JASON: Yeah. I was going to write a post about pizza but it was too cheesy. Okay. All right. This one's published.

JON: Awesome. Sure.

JASON: All right. So, we got one published, one un-published.

JON: Yeah. And then, well, we could either keep going through it -- well, how about we just jump to one of the very helpful things that you may to want look at if you're coming to Supabase as a first-timer. If you look in the side panel towards the bottom for API.

JASON: API!

JON: Yep! That's the one. This is autogenerated documentation for your Supabase instance. And so, if you want to do something, like get all of the posts -- and you'll see that we just created this posts.

JASON: I'm --

JON: Table.

JASON: This is already -- this is -- I can publish this publicly as well and say I've got an API. Here's my documentation for it?

JON: Actually, I don't think you can make -- I don't think you can make this public. But this is -- this is your personal documentation for anything that you create within your Supabase instance. It will automatically generate this information for you as you build it out. As you add columns and tables, this documentation is automatically being maintained for you internally. That would be very cool. That's an interesting point. Like if you could make this your actually, if you're building a developer-facing app or something like that. If you want to publish.

JASON: A good example is I put all the Learn with Jason episodes into a database and that goes on learnwithjason.dev. But I have an API, API/episodes and you can get all the episodes as JSON. If I could link to API docs. You have to look at the source code and realize that I have serverless functions that will give you a JSON blob if you query them. It's very high-tech here. Even internally this is huge. Because we spend so much time as developers chasing down documentation. Or getting stuck because the documentation drifted out of date. So, knowing that it's generated from the database schema directly and that it's kind of automatically maintained in the background is -- that's a big confidence booster, I think, in the quality of an API. And that's like one -- value props of GraphQL, right? And it looks like you're bringing that to a non-GraphQL use case.

JON: Exactly. Totally. Just getting started, exactly what you're talking about. That discoverability side of it. GraphQL makes it so easy to pore through what is available? That's automatically generated and kind of protected from doc drift.

JASON: Yeah.

JON: Because it's any time you generate anything, it goes in and re-generates your documentation for you. Cool. So, this is just, you know, I'll probably just tell you what to do anyway. But if you did want to come back and find things later, if you want to take it any further, this is a really good place to come and investigate. All right. Let's go back to your Next.js application and let's get those posts displaying in your app.

JASON: Okay. Back to my application which is here.

JON: Yeah.

JASON: I am going to -- well, we probably want to get static props?

JON: Yeah. Yeah. So, this will be how we'll -- yeah. Let's do that. GetStaticProps.

JASON: And if I remember that directly, to do that, we have to return an object that has props and do whatever we want it to be. And we probably want one that's posts which should be an array. Okay.

JON: Absolutely.

JASON: If that's the default.

JON: Props. You want to destructure posts, not props.

JASON: Posts, that's right. This is my posts. And then I'm gonna stringify posts.

JON: Favorite debugging trick.

JASON: My favorite debugging trick. Maybe I need to reload?

JON: Refresh.

JASON: Right. Because we added a getStaticProps.

JON: Yeah. It has to run the get servery stuff. Let's get those posts. Maybe create a different tools file for Supabase because we need to use it a lot of places across our application. Let's create a new folder called -- I always go utils. But some people like lib.

JASON: It doesn't matter. I've never cared. Utils and you want to name the file --

JON: Supabase.js.

JASON: Okay.

JON: Easy. And in here, we need to install the Supabase JS library. That's probably going to help us. Go back to the terminal.

JASON: I learned a thing that blew my mind. It's not gonna work because we have to restart the server. Let me show you the thing, I hit control Z and it suspends the running process. Now I can do a thing, I can do whatever I want in here. And then when I'm ready, I can type FG and it just keeps going.

JON: That's amazing.

JASON: This blew my freakin' mind. Like, so many times I've needed to just delete a file or like check a value and it doesn't affect the running process. And I have to stop it and then I have to wait for it to boot up again. Sean did that.

JON: It would like pick up the changes, right? Even if you quit it for a second, installed a package and then continued like it would just keep going.

JASON: It wouldn't pick up the package changes. You know what? We're going to learn together. Let's try. I'm gonna start it and then we'll suspend it. Okay. So, here it goes. It's running. All right. I'm gonna -- and just to make sure that that's doing what we want, I'm going to come out here. Add another. Okay. So, it's working. So, I'm gonna suspend it. Then we're gonna npm install. What's the Supabase package called?

JON: It's @supabase/supabase-js.

JASON: Okay. Anything else that I'll need?

JON: No. Not right now. I don't think so.

JASON: Okay. So, now I'm gonna resume the process. So, we continued Netlify Dev. And if I come back in here, and I save, we're now hot reloading again, right? So, this is magic. Now let's see if the real magic works. I'm going to try to import the package that we just installed and see if it doesn't explode. So, it's Supabase --

JON: So, it will be destructuring as in importing names. A named export.

JASON: Okay.

JON: So your are brackets, and then createClient.

JON: It looks like it might have picked it up from @supabase.

JASON: All right. There we go.

JON: Well, yeah. We need to store in an environment variable. We can test if this is working before we do that. We can say export_default and then that createClient function. And this is a function that takes two string values. It takes our URL and our Supabase key.

JASON: Okay. So, the API key I need so we will have to stop and restart the server for that so we can get it to pick up environment variables. Is it the public API key, though?

JON: So, this is the cool thing about -- about Supabase. Is that when we have security enabled, we can expose our API -- anonymous key. Oh, look at that dab! To the frontend and that's completely safe. But these little hackers you have watching your stream right now, before we enable --

JASON: Will go and make a mess. I know, I know.

JON: Keep going. All right. Let's just do process.env. With the URL let's roadway place with process.env dot --

JASON: And we'll call it SUPABASE_API_KEY.

JON: And we can expose this to the public. Next_public.

JASON: The next public prefix means anything we prefix with this will get put into the public bundle. For anyone who is not familiar with the convention. We are exposing this. Don't do this for something that's secret. If you put next public in front, it's going to show up in JavaScript bundle and everyone will make a mess. Welcome Anthony and everyone who came along, good to see you. I'm super-excited to see everybody here. Aiden is watching live. Aiden is part of the team that keeps Learn with Jason on the rails. He's in New Zealand. He never gets to watch live. This is fun! This is fun! We have firsts all over the place.

JON: That's awesome.

JASON: What should my URL be?

JON: You can do next_public_supabase_URL.

JASON: Got it, all right. And then we're going to -- actually, it should -- yeah, it will autoformat.

JON: Who is manually doing formatting these days? Come on!

JASON: We've got this. It's doing what we want.

JON: Correct. So, let's --

JASON: So, I need to set these.

JON: Yes. Because you're using Netlify Dev, you can just that directly, can't you? That's cool. Next underscore.

JASON: I'm going to copy/paste so I don't have to type this multiple times.

JON: Cool.

JASON: What I'm going to do is copy-paste this.

JON: This comes from settings. This directly here.

JASON: Where did you go?

JON: Scroll down again.

JASON: Did it run away?

JON: You've deleted your key. It's done. No. Settings --

JASON: It's over. I need this one.

JON: API. Yep.

JASON: Okay. Now, I'm not gonna paste this now. I don't trust you hackers.

JON: Oh, that's your URL -- that's your key.

JASON: Oh, you're right.

JON: URL, which is just slightly down if you scroll down.

JASON: You hackers, you dirty hackers! Damn right, you hackers. Now I've got my URL. Can this one be shown?

JON: This one can be shown.

JASON: Let's show you how this works, this is Netlify-cli, and then env, value set and then the name of the value. And it will not do anything because we didn't set up a site yet. That's right. So, here's what I'm gonna do. Is I'm going to first get this site set up. And then we've got all this stuff that we need to do. So, I'm going to get add everything. And we'll get commit and we'll say, you know, work in progress: Setting up a Supabase-powered blog. And then I'm going to GitHub repo create and we'll create learnwithjason/supabase-blog. All right? It's gonna with a public repo?

JON: I think maybe you have done this before. Maybe once or twice.

JASON: And honestly, it's so nice to have this GitHub CLI and the Netlify CLI. We can do it all from right here. I'm going to set the push U to get the upstream and origin main and that's going to push everything up to GitHub. And so, now, this opens to the right thing. Here we go. This is the -- here is our GitHub. So, you can go check this out. This is the work in progress. We'll push all the changes there. And then what I'm gonna do is I'm going to Netlify init. Now, I broke something in my GitHub config. That might explode and I might have to set it up manually. But I'm going to try it anyways. I'm going to set up a new site here. And wear gonna call this Supabase blog and it auto-detects all the next stuff. Good.

JON: Just so nice. Netlify is --

JASON: Yeah, my GitHub setup is still wrong. I'm going to set the rest of this up manually here. The details are all in place. I'm going to hook up the Git part. Site settings, build and deploy. And then I got to link to Git. I need to log out of Git and try this again to fix it. But we'll get there, don't worry.

JON: It's so nice using the setting environment variables directly through Netlify theme. Using the Netlify Dev, it's something I never think to do. Takes away the step, you get the changes, and deploy and get the error, you haven't set the environment variables for the thing you're working on. It takes away that whole problem. It's awesome.

JASON: Now that we've done this, I'm going to run this Netlify M set. It said it set the thing and we can check it with env: List. And this will show the environment variables. And if we wanted to show it, we can hit the yes and show they're there. And if I go back out here to the site settings and build and deploy at environment. I've got to refresh the page. We can see that it showed up here. So, the next thing then is we want to do that same process. Env: Set. And I'm gonna go copy my this one and then I'm gonna go back here. Copy this one?

JON: Yep. You can't see it all there, it's fine. You want to take this off screen.

JASON: I'm going to take this off screen.

JON: It's only because we don't trust you. It's not because you shouldn't expose this to the frontend. We just haven't clicked the little button that makes it safe. If we could trust you, it would be fine.

JASON: Look, chat, it's not that this is the problem. That's you're the problem.

JON: Yeah. It's not me, it's you. This is entirely safe to put in the frontend once you have row level security enabled. Which we will do in a moment. But at this point, putting that in your frontend would allow people to write to your database. Do whatever they want. And so, but -- yeah. Just know it is okay to expose this in your frontend once you have the security enabled.

JASON: Right. We have set the value and we are -- it's now functional. So, when I run Netlify Dev, it will pull in those environment variables for us. And this will also now be available when we deploy. So, this is -- this is running. We're in good shape here. Let me get in here. And so, I have a client now. But we aren't doing anything with it. So, I'm gonna make the assumption that I want my clients.

JON: Yeah, you want to pull it in. Yep.

JASON: Supe -- nope. Utils. Supabase. All right. Got it.

JON: And then, we want to request our data. So, we can say, Supabase -- well, yeah. So, this will be an async thing. We need to make our get static props an async function.

JASON: Async function. Got it.

JON: And then const --

JASON: Await.

JON: Supabase --

JASON: Should I call this Supabase?

JON: Uh, yeah. Sorry.

JASON: All right. So, Supabase dot.

JON: And then we do .from. Yeah. We've got helpful little --

JASON: Let's see if I can do it.

JON: All right.

JASON: I did Supabase .from. And when I got in here, it said from the table. Okay. That's a string. So, I'm gonna put in the name of the string. Then I'm gonna do a dot and it says here select. That makes -- okay.

JON: Look at you go!

JASON: And column, string head count.

JON: That's a little less fun, isn't it?

JASON: What if I do this?

JON: Ah! Look at him! Wow. Are you sure you didn't try Supabase before this?

JASON: No, I'm using what little knowledge I have of SQL. When you do MySQL, postgres, you do select star from table. I'm seeing, we're doing a from. I'm selecting and this is my guess at all. But this is actually the end of my guesses here. Because I don't know what happens next. Is this everything?

JON: Almost. So, just the posts.

JASON: Okay.

JON: We would destructure the data that comes back so we could -- we could make that curly brackets and just do data. And then we could still do colon posts and that's gonna --

JASON: Got it.

JON: Posts directly.

JASON: Do we get an error or anything?

JON: We do get an error. If you want to be that pessimistic. We can do to properly and look at errors and things.

JASON: Do it like that. Basic defensive programming. Make sure that if you get an error, you don't end up with a confusing uncalled exception. You instead get what the tool said. I found that a lot of my debugging pain comes from having not done this. Where I'm like, it'll work. And if it doesn't work, it's like, uncaught exception. Zero additional information. Great. That's gonna be fun to debug.

JON: Yeah.

JASON: And then --

JON: A developer put in the work to actually send us a proper error. We may as well -- we should do them proud by actually reading from the error message is. Yeah. Now we have our posts and everything should be fine. We just need to refresh.

JASON: Ayo! Look how fast that happened, everybody.

JON: Beautiful.

JASON: This is custom database, we set up environmental variables. I'm not gonna deploy it yet because we haven't locked down the rows or anything. We're done. We have the environment variables in place, a site set up. This can go to production rite now. A beautiful site.

JON: It's so beautiful. Yeah. Let's do that. Let's lock down those tables and so we can publish every places.

JASON: So I'm going back to table editor?

JON: Yeah. You can click it directly from here. If you select posts and RLS. Or you can go through authorization and then policies. Which is where this is taking you.

JASON: Got it, got it, got it.

JON: And then we want to enable RLS. What row level security does is it just locks down every action by default. It just says I'm going to automatically deny any request I get. Select request, update request.

JASON: This is gonna fail. Nothing.

JON: It doesn't fail. It just goes back to an empty array.

JASON: Got it.

JON: It's not that you don't have -- it's not that you're doing something wrong here. It's just that you don't have the authority to see those posts anymore.

JASON: Okay, okay.

JON: If we wanted to enable that. You're not getting an error saying you're not authorized or anything. Because that's not the case. It's just that you don't have the authorization to see any of those rows at the moment. If we want to write a rule to allow you to see some of those rules, we need to create a policy.

JASON: Okay. I'm going to click new policy.

JON: And we can create a policy from a template, show you what this looks like if you click there. We have a lot of pre-filled templates that cover those basic use cases. You don't have to get overwhelmed with having to write a policy that you're not familiar with.

JASON: Cool.

JON: We have the ability to give read access to everyone. The ability to just do authenticated users. And if you click on any of those, it will show on the right what those are. It's very scary.

JASON: It's very SQL-y.

JON: It is very SQL-y. Go back. And in the top left, there's a back arrow. And create it from scratch. This is all we're doing.

JASON: I want people to be able to read the title, date. I guess we can let them read everything in this database, don't we?

JON: So, a row level policy is the entire row.

JASON: Oh, got ya.

JASON: We either enable or disable the whole row. We can't do it column-by-column which is where your mind went. If we want to have the read access if the column. Can't do that with row-level security. But what we can do because we have a relational database, you can put that kind of private stuff in another table and just set up a relationship between those two. Anyway, we're not gonna go that deep here. But I'll give a plug for an Egghead course that I just created at the end of this and that definitely steps through that use case.

JASON: Okay.

JON: Let's think. What is the actual rule that we want here? We don't want everyone to see -- so, just imagine someone's coming to this list of blogs. Which blogs would we like them to see?

JASON: Oh, we want them see the published ones.

JON: Exactly. Yeah.

JASON: Is it just like a where is publish?

JON: Don't even have to do a where. Don't need to do that. But you're right, it's published equals true.

JASON: That's all?

JON: That's all we care about.

JASON: Slick.

JON: And that's going to show you what that turns into. That's the actual SQL. What we try to do is educate you along the way. We don't want to just completely abstract. Don't worry about the SQL, you don't need to know SQL. We like to have the opportunity to teach people a little bit about... [ Laughter ] Yeah. Like it's already working. It's amazing. And so, yeah. Like we want to show you as much as we can along the way to see kind of like what the Supabase tool is abstracting away from and making it a little bit easier. But also, if you wanted to do this, you can do it. And so, yeah. If you enable that one. We go back. Refresh.

JASON: Ta-da! That's really slick.

JON: Yeah. And so, since this is just a wrapper around SQL, on the left we actually have an SQL editor. If you go -- I think it's about halfway down.

JASON: Ah, yeah.

JON: That one. And from here, we can create a new query. So, again, we've got some templates if you want to look at some cool stuff. But yeah, if we click new query, we just get -- what's this? Done its thing. This is just a portal into our database. So, yeah, you know your SQL.

JASON: I know that much SQL. Let's see if I can do it.

JON: That's about all I know as well. It's fine.

JASON: Hey! I wrote SQL! [ Laughter ]

JON: And so, this is like -- I don't want to say there are no limitation on it. You're still logged in as a particular user of this Supabase instance. And so, there will be certain things that you might not have permission to do. But this is basically just a --

JASON: Whatever you have permission to do as a postgres user you have permission to do in this portal here.

JON: Yep, exactly. Yeah. This will bypass all row level security stuff. At this point, you're like a much more elevated privileges than the users of your application. Like you're basically a database administer. So, you can insert things, you can update, delete, whatever. You can change the structure. But this SQL editor here is like it's just an open portal to your database.

JASON: Yeah.

JON: Actually, if you go back to that getting started welcome bit on the left.

JASON: Okay. Welcome.

JON: If you scroll down, I think we actually have some quick start like whole databases. So, if you like --

JASON: Oh, cool. Yeah.

JON: Stripe subscriptions, for example. If you click that one. Once it loads. If you scroll through this thing, there is just like all the stuff that we give you. And so, yeah, we have some templates that you can create.

JASON: Got it.

JON: Some very advanced things.

JASON: Policies and all that stuff. That's cool. That's very cool.

JON: We don't need to touch the editor.

JASON: I want to do a quick time check. We've got about 20, 25 minutes left. And I want to make sure we get through everything that we want to get through. Because we haven't yet gotten to authentication or realtime and I want to make sure we get to play with both a little bit.

JON: All right. Let's quickly create a post details page. Let's create a new page.

JASON: Okay. So, let's make this out here and we -- this is gonna be like a... one of these, right?

JON: Oh, yeah. Yeah. Let's just do ID so we can speed it up a little bit.

JASON: ID works. ID.

JON: And then we want to --

JASON: Export static -- oh, wait. Export async function_getStaticPaths, right?

JON: Well, for this one, because we want to display comments as well, we should probably use get server side props. Yeah. Because that's going to change regularly. We could do -- yeah. We could do -- other things. Yes.

JASON: Okay.

JON: That is the thing.

JASON: All right.

JON: And then we want to say const data, same as before, destructuring data = await Supabase. Just one post.

JASON: You know what? How about I just copy-paste this out?

JON: That's a great idea.

JASON: I'm gonna copy-paste this part out and go in here. And we'll just do one of those. And how about that? All right. So, we got one of these.

JON: So, we'll just be getting one post rather than all of our posts. And it will -- so, we need to tell it which post we actually want to select. And so, star is still fine there. We can still grab all of --

JASON: No, not like that.

JON: Almost. Almost.

JASON: Almost, almost, almost. Okay.

JON: Something I should have mentioned before, you can actually just list the columns here. Star is getting you all of the columns. But you could say ID and you could say name, or title. And so, that kind of addresses one of those other concerns with GraphQL. You don't want to over-fetch things. You want to specify the bits of data you care about. You can do that in the select. We want the equals.

JASON: Column ID.

JON: Yep, that's the column. And the column that we want to match is params ID.

JASON: Perfect.

JON: This is going to give back an array even though it's one value. You can add a .single to the end of the request.

JASON: Like that?

JON: Yep. And save that and nice formatting and then props.

JASON: Props, props, props. And then the post. Okay.

JON: Yep. Singular post. Destructure that out of into our component.

JASON: Okay. And then we've got export default post page. And that's gonna get out our post. And this is going to return. We'll give it a div. And ideas of our div we'll do an H1 with the post.title. And we'll do it --

JON: Paragraph with the post --

JASON: And with the dangerously set inner HTML.

JON: We won't be dealing with --

JASON: We don't need that, do we?

JON: Right. If you want to build your own mark downy stuff. You can do that.

JASON: Content. Export, default function. It's why that's throwing errors at me.

JON: Cool.

JASON: So, this theoretically should work.

JON: Yeah, theoretically.

JASON: Make sure it's still running. I'm going to go to slash 1. No, it doesn't like my --

JON: Ah, you might need to be error.message in the... yeah. Error.message, I think.

JASON: What have I done?

JON: And then if we refresh the page, we should see our error.

JASON: It doesn't like my error.message. What am I doing wrong here?

JON: Error.message.

JASON: Whoops. Let's go in here and maybe let's just try console.log. And --

JON: Yeah, just console.log. That's enough.

JASON: What are you yelling at? What is happening? Cannot read --

JON: Is it not called title? Did we call it?

JASON: No, I think something's going wrong with the actual thing.

JON: It's not actually getting it in there.

JASON: Requested or multiple or no rows returned. So, we need to check what is going on -- oh, wait a minute. I have... let's... let's log params and see what we're getting here. Our params are 1 is a string which sing the problem. So, we need to number... is that gonna make you happy? You're still not happy.

JON: No, you should be able to pass a string across.

JASON: Okay. Did I... is it not ID? It is ID.

JON: No, it is ID.

JASON: ID is 1. Chat, you seeing something we're not?

JON: Await, Supabase.

JASON: Let me log params.id. Oh, wait, wait, wait, wait. That was a good -- that's the one that's not published. Let's go to 2. Good catch, chat!

JON: Damn RLS getting in the way.

JASON: That was gonna be -- but you know what? Great. That's perfect. So, it was telling us that nothing was getting returned and if -- yeah. So, good. That's --

JON: Once again, the computers were right. Look at that! It's never me. I'm never the one that's right.

JASON: You're audio is working fine. But your face is frozen in like the most judgmental look. Really...

JON: That's just my face. That's how I look at all code all the time. It's just -- hm. You're not going the right thing.

JASON: Good catch Alastair Young, thank you very much for that. So, we've got this post going now. Look how fast! Look how fast it went. All right. Let's add some more.

JON: Let's create a login page.

JASON: Okay. Login page. Okay.

JON: And in here, we want to export out a --

JASON: You know what I'm gonna do? I'm gonna take this part and copy-paste it for time. And call this login page. And does this need any props or anything?

JON: No. But we will be -- we'll have to deal with forms which take a while to write in React land. But let's create a -- a form with an input.

JASON: Okay. And our input -- let's do, we'll do a label, htmlFor. And that's gonna be for the -- I'm assuming --

JON: Email.

JASON: Email.

JON: Email. And for this one, we might just use magic links so we don't need to create another password. They support link and password, or magic links. We click on the link and we're authenticated. If we want to enable third-party authentication, that's -- we just need to enable some more stuff in Supabase. But for now we'll just do our trusty magic link. Okay. Cool. So, when we click submit button. We can put an un-submit on the form and write a handle submit function that will run when our form submits. and this one is going to be async.

JASON: Prevent

JON: Prevent default. That wonderful JavaScript-y thing.

JASON: And then to do an onSubmit.

JON: On the form.

JASON: HandleSubmit. And now we'll do the thing.

JON: Yeah. we can grab the people out of our form saying const email = event.target.email.value.

JASON: Okay.

JON: And now to authenticate with Supabase, you can say await. If you want to do the proper handling we could. But do Supabase.auth.signIn. And sign in, it will suggest camel case. Give it an object and we can pass it our email. That should be all we need. Let's see if it works first. Before we claim that this is all we need.

JASON: All right. Let's see what -- let's see what happens. So, I'm gonna put in Jason@lengstorf.com. If I spell it right.

JON: You need to check that, the magic will go to that. Check it offscreen if there's sensitive things in there.

JASON: So, it did the thing. I'm going to pull the email over here.

JON: We could have written some logic to give us some feedback there.

JASON: I just got an email here that says confirm your mail. So, I'm going to confirm. And it opened up in this browser. Which we haven't handled yet. So, I'm gonna get my email out of the way.

JON: If you open up your console and go to the application tab.

JASON: What the -- what is that? No, here. Console. Application.

JON: Application. And then go to local storage, I guess. For what we're currently logged in as and you scroll down. Okay. There's no key in there.

JASON: It didn't hit our login page. Do we need to have it -- do we need to set up a redirect or anything? Like do I need to go to login?

JON: No. That should be fine. We should just need to refresh. Just go back to local host.

JASON: I think it's -- yeah. I'm not 100% sure. But it looks like as soon as I went to log in, it did the thing.

JON: Good call. We did need to go back. Now you're logged in. If we go back to the index page, we could console log out who our user is just to confirm that we are logged in. So, the way that we access the user, if you just want to do console.log. And then we can say Supabase.auth.user. And user is a function. And save. And then refresh and open your console.

JASON: Now... this one. Open my console. And there it is. Hey!

JON: Yeah.

JASON: That's pretty straightforward. That just did what I wanted.

JON: Yeah.

JASON: We have roles in here, I could imagine we could get pretty fine-grained with those.

JON: Absolutely. And if we were to authenticate with a third-party provider, Google or Facebook or something like that, then we get the information we get back from them.

JASON: That's slick.

JON: What your username is for GitHub or whatever. And so, that's how easy auth is. Now we're authenticated. Let's add some comments so that I can also have some fun and write things on your page. Sensible, you know, nice things.

JASON: Sensible, nice things, chat.

JON: sense suitable for work. are you ready?

JASON: I'm ready.

JON: Let's go back to Supabase and let's create a comments table.

JASON: Okay. Got a table. I'm gonna create a new one here. And I'm gonna call this comments.

JON: And then what --

JASON: Yes.

JON: Yeah. Let's do it.

JASON: Okay.

JON: You know how this works now. If we add a column, we're gonna want a column for -- this is what's going to be called, if we go back to database theory, you don't have to know this. But it's called an intersection table. We basically want to give this a relationship with a post. So, we want -- each comment is going to belong to a post and also belong to an author. We want a post ID. That's right. Before you click that, though, we can actually just click that little lock symbol next to -- yep. And this is going to allow us to set up a relationship with the table that we want. And, we can say that links to the post's ID.

JASON: Wow, that was easier than I expected. Beautiful. Okay.

JON: Now let's add a column for user ID.

JASON: Okay.

JON: And for this one, it exists on auth.users. So, this is a special table --

JASON: Come on, come on.

JON: Change to ID. This is a special a table that Supabase manages for us any time we log in. And then we want the actual content of our post.

JASON: Beautiful. All right.

JON: And now we can save that.

JASON: Okay.

JON: And one thing we could have done, if you click the little cog, you can make it -- yeah, you've got some extra options to make it not-nullable or whatnot. The place that's in place now because it's in the key relationship will stop it -- never mind. Forget I said anything. Database, database, database. We don't need to worry about it.

JASON: My default. You know what? Let's just pretend I wasn't talking.

JON: I was rambling.

JASON: We want to do a new policy. And we want to allow...

JON: Well, firstly, let's go back to your code and see what we need to modify to actually -- to actually see this.

JASON: Sure.

JON: Let's go the TDD route. Let's see that it doesn't work and then we'll make it work.

JASON: Okay.

JON: So, this is your statement. You're grabbing all the posts. Might think I need to get a different statement to grab all of my comments.

JASON: Literally what I was about to do.

JON: Because we set up the foreign relationship between the two, Supabase knows that the posts have related comments. Where you're saying select, select star, you can put a comma after the star and tell it all the tables you want to select from. All from posts, but then comments and then in brackets we do rounded brackets, parentheses. No, not those squares, the other ones.

JASON: Round boys.

JON: Round boys. And you tell the round boys what you want to select. In this case, we do the star again. And then close your round boys and save. That's it. That's all we need to change.

JASON: Get out, come on.

JON: We're grabbing their associated comments.

JASON: Okay. So, this --

JON: But...

JASON: Didn't do --

JON: Oh, was that -- which page did we just do that on? I think we just put that on the index page, didn't we?

JASON: No, I put it on the ID page. But we also didn't log anything and we're not like dumping anymore. So, this makes sense. There's nothing to see, right?

JON: So, in our component, let's just -- yeah. Why don't we do a pre-tag. Yeah. Good call. And then post.comments.

JASON: Oh, dot comments.

JON: Or just the post.

JASON: I was gonna see what we get. So, question get an empty array for comments.

JON: We don't have a policy yet.

JASON: And get comments in the database.

JON: That's a good point. We should probably put a comment or two in there.

JASON: Let me go in here. I'm gonna do -- nope. Comments.

JON: Yeah.

JASON: Insert a row. Is it gonna let me do the things

JON: Yep. You can click --

JASON: What?

JON: Go in and look at the other database. If you close that and put in the number 1.

JASON: 2 is the one that's published so we can actually use it.

JON: Good call. And 2, click data and link to the other one.

JASON: Yes, got it. Okay. Very cool.

JON: It would be nice in the future you would be able to click and navigate through the other table. But at moment we can't. Now you need to know what your user's ID is. And so, yeah.

JASON: I'm gonna get my user ID out of here because we logged. and that ID is this one I assume?

JON: Yep. That's the one.

JASON: On I go to here, get rid of the quotes.

JON: No quotes.

JASON: There's me. All right.

JON: That looks like the one. Close. And what do you want the comment to be?

JASON: Ah... [Concentration face]

JON: Awesome. And now if you refresh back in your application, do you expect to see it or not to see it?

JASON: I am expecting not to see it because we got bit by this before when we turned off the row level security. But we know how to fix that.

JON: We do.

JASON: I go back here and go to authentication and policies and new policy. I'll create a new policy. And public read all comments. And we want...

JON: So, you're stumped, aren't ya? What do we want? Really we only want to see a comment for a post that is published, right?

JASON: That's true, that's true.

JON: Because this has a relationship to posts, we probably want to rely on the policies that we've written for post and enforce them on comments as well. So, this will get slightly more scary than the other SQL that we've written, but not really.

JASON: Okay.

JON: Let's go. Select star from posts. So, we can just write a regular select statement and access other -- other tables. And we want that where the -- let's make it a little bit more specific and say post.is published.

JASON: Where posts --

JON: No, sorry. That's just -- this is selecting all of the posts that are published. What we want to do is select star from posts where posts dot... what am I trying to say here? Post.ID. We want to check whether the ID is equal to our comments.post_id.

JASON: Like that?

JON: Yes. So, this rule is going to run for every single row that we're checking whether we can read it or not. And so, this statement, select star from posts where post the.id = comments.post_id. For the comment I'm looking at, it has a post associated with it. Go and look at the post table, and whether we can select that or not is based on the rules of the post policy rather than the comments policy.

JASON: Got it.

JON: Before you go back, one more to this. Which is basically select. We want to see if this statement gives us anything back. If it gives us anything back, we're allowed to see the comment. If it doesn't give us anything back, we're not allowed to see the comment. We to want wrap the whole statement in exists.

JASON: Like that?

JON: Yep. And then since we don't -- this is just a slight silly optimization. But since we don't actually care about the columns that come back, we can just replace the star with a 1. It's only going to return us true if it can or false if it can't.

JASON: Got it.

JON: If that exists, then we want to enforce this. If you say review and then save that.

JASON: Save.

JON: So, really, all we're doing is saying that since the comments belong to the posts, let's just apply all of the policies that exist on posts. And that's what that statement does. It looks a little bit scary, a little bit gnarly if you're not used to SQL. But now you can see that we can see all of the comments for the post that is published. And if we... if we were trying to view the post that wasn't published, we were trying to view a particular comment for that --

JASON: Right.

JON: We wouldn't be able to see it because the post isn't published. If we want to write policies for how a post is published, that will flow through.

JASON: Okay. Really quickly. I'm going to add all of this. Git commit. And we're going blog with comments and row-level security. Okay. Good. Push. Now everybody will be able to see that in a second once it's built. Which it should be building right now.

JON: And very quickly add realtime. Realtime. 5 minutes. Let's do it. All right. So, we want to be able to subscribe to new comments that come in. On this one, let's bring in useEffect.

JASON: Okay. Oh, React. Okay.

JON: Yep. And let's call useEffect as a function. And then initially we're just gonna do it on mount. But we will add square brackets in a few seconds to write things properly. And then couldn't subscription = and don't need the await. And then Supabase.from and then comments, and on, and we have the different events. Let's just go insert and then we can also pass that an arrow function which we get a payload for.

JASON: Is that straight up like that?

JON: Yep. Yep. And then just an error function. Just console log out what our payload is. And then... after all of that, let's do -- chain on a .subscribe. Yeah. Where that semicolon is.

JASON: And back to unmount, we want to do return subscription dot --

JON: Almost, we want to -- I think we need to -- because we need to pass it the subscription we want to unsubscribe from, yeah, we need it to be an error function. And then we just pass it the subscription.

JASON: This is the subscription that we created.

JON: Sorry, we want Supabase remove subscription.

JASON: And then pass in --

JON: The subscription that we just added. Save. And actually because we're now relying on Supabase... yeah.

JASON: Here. All right.

JON: Let's just go and look in here.

JASON: No, why did you fail.

JON: Let's refresh. Oh, yeah, right. We haven't actually told that table that we want to listen to those events.

JASON: We also stopped the Dev server.

JON: That doesn't help. Back to Supabase quickly. Show you how you enable it for a particular table. You go there and then to database. This is a special thing called replication in the database world. Find the replication. You want to click where it says zero tables. And we want to enable comments.

JASON: Got it.

JON: And so now any of those events will now be fed through anything that's subscribing to them. So, if you refresh that page. And then you go to your Supabase database and you add in a -- a new -- you know how to do it. You know how to demo this. Perfect.

JASON: All right. Let's get a new --

JON: Oh, the UI might not be super-useful.

JASON: We can make it work.

JON: Beautiful.

JASON: I have a few post ID. My post ID is gonna be 2.

JON: Yep.

JASON: My user ID is still in my clipboard.

JON: Ah! Look at that!

JASON: And now I need... do the thing, do the thing. Come on. First try. Oh, it's beautiful! And so now what we would do if we had more than 1 minute left, we would create, we could use the React use state hook to put our comments in and we could -- we could then monitor for the event to change. Update with the new thing because we've got new... here's the new thing. So, we could basically just throw that right in.

JON: Yep. So, new represents that whole row. That's the whole row that's being inserted. Yes. You're right. Create a use state variable for the comments. And any time we get the event, spread in the existing comments and add that payload.new.

JASON: Hot damn, Jon. This was fun. We got so much done. I am very pleasantly surprised with how quickly we were able to do all this stuff. I know when you were giving me the heads up, yeah, we're going to do a database and a website using that database and then authentication for that database and then comments and then realtime. Zero chance we're getting that done. We'll pick a point to end and be good.

JON: To be fair, I was thinking the same thing. I didn't actually think we would get through all of this. I'm impressed.

JASON: This is incredible. Let me push this now. Add realtime subscription for new comments. And we'll push that up.

JON: Yeah.

JASON: And that will deploy. The deploy should be done here. And so, yep. There is our blog. And if we go to --

JON: So, question just need to take that URL -- just quickly we need to take that URL and add that to our Supabase auth settings just so someone can log in. Otherwise they would be forwarded to local host.

JASON: Like that?

JON: Site URL. Just load --

JASON: Don't do this to me.

JON: That's the one. And that's all we need to change. And it's now production.

JASON: All right, y'all. You can go and play with this right now. Check out the login, check out the loading of data and all those things. And clone it, set up your own Supabase and mess with all these settings because this was really, really fun. Jon, where should somebody go if they want to take next steps?

JON: If you want to take next steps, check out my new Egghead course. Search egghead and probably just SaaS. Or egghead.io, it's probably in the what's new button.

JASON: Oops, clicked the button. It's just SaaS?

JON: In this course, we go all the way from an empty project all the way through to actually having a real subscription-based billing service that actually charges people real money in production. And so, yeah. I highly recommend you check this out. Goes much more into depth in the things we covered here and much, much more. It's a great way to learn what Supabase has to offer.

JASON: Great. And check out Supabase.com. Make sure that you are looking at Jon on the Tweeter so you can get all those details and get this really unsettling profile picture in your stream every day. And let's take a moment to shoutout to the live captioning. We've had Amanda here all day from White Coat Captioning. Thank you so much for being here. Made possible by our sponsors, Netlify, Fauna, Auth0. They make it possible. We have so much good stuff coming on. Including n8n later this week, Harshil Agrawal will be here. And next week, a week on music. On Tuesday, Dan Gorelick is going to teach me how to make music with code. Algorithmically-generated music. It's going to be so much fun. And then Char Stiles is going to take whatever Dan and I build on Tuesday and build an on the fly visualization using code. So, really, really powerful cool stuff. I'm blown away by the work that these two do. Can't wait to learn a little bit how to do it.

JON: And Winamp there. Spotify just doesn't cut it.

JASON: I miss Winamp days. They were the best.

JON: Beautiful.

JASON: Ben Holmes is going to come. He's actually debuting the renderers for different things, if you want to use Vue or Svelte in Slinkity. That will be here. I'm looking forward to everyone being in here. Get your calendar marked. You can put this on Google Calendar, you can do a follow on Twitch, that's free. And it will just let you know when we're live. You can follow Learn with Jason on Twitter. All sorts of good ways to get involved. We would love that. I think we're going call this one a win. Jon, any words for everybody before we call this finished?

JON: No. Just go build some cool stuff. Tells what you're building. Hit us up on Twitter and we would love to share it.

JASON: We are going to raid Prince's stream. Make sure to show some love for Prince. Chat, as always, thank you for hanging out with us. We will see you next time.

JON: Thanks for having me. This was awesome. See ya!

Closed captioning and more are made possible by our sponsors: