PlanetScale Serverless Driver, Netlify Edge Functions, and Next.js
with Jason Lengstorf
PlanetScale just released a serverless driver for Netlify Edge Functions that unlocks some very cool possibilities at the edge. Let's spend some time digging in and seeing how it works in this episode.
Topics
Resources & Links
- https://www.learnwithjason.dev/topic/planetscale
- https://rustadventure.dev/
- https://planetscale.com/
- https://planetscale.com/blog/introducing-the-planetscale-serverless-driver-for-javascript
- https://deno.land/manual@v1.24.3/node/compatibility_mode
- https://www.jason.af/uses/
- https://www.learnwithjason.dev/schedule
- https://app.postal.io/l/0r8sqq2n
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 are going to be -- it's just me. Sorry. You're stuck with me. It's going to be that kind of day. But don't worry, chat, because it's still going to be really fun. We have some actually -- I'm really excited about this. PlanetScale dropped this super cool database driver for JavaScript. It's a serverless database driver. And it works for Netlify Edge Functions. As we know, PlanetScale also has this really cool idea of portals, where you can deploy your database to different regions around the globe.
So this gets us pretty dang close to something that I've been really excited about, which is databases that actually live closer to your users. So let's take a moment and reflect on how freaking cool it is that we can now go to -- woo -- okay. This is school. I got to gather my thoughts here because we got something pretty exciting going on.
We've got front-end developers, what we would traditionally call front-end developers, who are now able to go to the PlanetScale UI, click a button, get a database. So no database provisioning. You don't have to be a DB admin. You don't have to figure out how to lock down permissions on a server, set up firewalls, all these things. So one problem solved as a front-end. Click a button, get a database.
Now you have the next problem, which is global availability. You want something that is, you know, if I'm in the United States, I want to write to my database quickly, and typically that works well in the United States because a lot of databases are located in one of the AWS centers, like US East 1, which means it's pretty fast. But if I'm in Australia, I'm still writing US East 1, and it limited to network latency but also the straight-up speed of light. It takes like 100 milliseconds for something to get around the world. So you have automatic latency built in when you're deploying databases far away from your users.
So PlanetScale solves that. They let us say we can make our databases multiregion. All I had to do was click a button, and now I'm a front-end, but I've deployed a database that's scaled and secure. Awesome.
Now I need to actually get access to that database in my applications, which traditionally would have gone to a back-end engineer. But because we got the serverless driver, we're going to be able to just import a package and put in our username and password that will get from the PlanetScale database -- or from the dashboard. And then we can just query stuff from our database. So this is really powerful stuff because you are not -- if you are building on the modern tools out there today, you are not a front-end developer anymore. You're a web developer, and you're absolutely capable of building full-stack apps, and you don't have to become an expert in a lot of deep areas. I think that's so freaking cool because it really points to this idea that the learning curve has changed, right.
I think when we were building websites back in the day, like in 2003 when I was first getting into websites, you were -- like the front end was a very specific thing. Then all of the things that happened that were dynamic were like in a PHP server. You had to figure out how to deploy Apache or get EngineX configured. Whatever those things were. Then you're provisioning virtual private servers, a VPS, or you're using shared hosting and dealing with FTP. You just kind of starting getting into all of these back-end things. Then it started getting more confusing. Now docker containers or Kubernetes or all these things. We can figure out this stuff out. This is our job. We work in tech. We can learn anything.
But the problem is that as these capabilities scaled out, it was too many things. Like, even with a lifetime of study, the likelihood that you can learn everything you need to know about DNS, everything you need to know about Kubernetes, everything you need to know about security, everything you need to know about networking, and also learn all the things about CSS and HTML and accessibility and JavaScript, the list just goes on and on and on, right.
But then with the introduction of these tools, with the introduction of things that give us all of these capabilities, we just -- all we need to really know is HTML, CSS, the accessibility that comes along with writing good HTML and CSS, and then you just need to know JavaScript. Because if you learn the JavaScript, you can use APIs to access all of these software as a service, database as a service, platform as a service, edge functions, serverless functions, et cetera, et cetera. Now you're writing full-stack apps. You're a full-stack developer with a front-end skill set.
So I'm not even saying front end, back end anymore. We're just web developers. We build web experiences. And this is coming at a good time because as of 2020, we saw the whole world move online. And we needed those. Like, what we used to do where we would go to a website that would direct you to a storefront or go to a website that was kind of like the banner they would wave before you came in and met somebody in person, that's just not true anymore. The vast majority of web experiences are like the whole experience. Your whole business is a website now.
When I go to my bank, I've never been to a bank branch of any of the banking institutions that I use. I went to their website. I signed up through the website. I uploaded an ID to verify my identity. I hooked it up to a different account. I transferred money through. And now all I have is the web experience, the dashboard for those accounts. I've literally never seen a person. I don't know if anybody works there. It could be a completely automated system. I would have no idea because the only way I interact with it is through the web experience.
So front-end developers being in this position where we have so much power because of tools, not because we're like suddenly studying more and more things, but because the learning curve is flattening. The accessibility to these tools, our access to build really complex experiences is requiring a narrower and narrower skillset because of amazing things like PlanetScale and these other tools out there giving us the ability to build more powerful experiences without having to become experts in every single vertical out there.
So anyway, all of that is preamble because it's why I'm so excited. It's why I wanted to put this on the calendar to play with this. Before we get into that, how the heck are you, chat? How you been? I'm seeing lots and lots of cool things in the chat here. People shouting out FileZilla. Cute FTP. Jacob with the sub. Thank you very much. Lots of familiar faces. Ben, thank you for the sub. Kuubitti, thank you for being here. Thank you for showing up to the stream. Who else is here today? Nicky, what's up, Nicky. All sorts of folks in here.
So you know what, I'm good. I'm good. Doing great. What's up, Alan? Yeah, I'm like -- this is an exciting week for us. Little wink, wink, nudge, nudge, pay attention because tomorrow is going to be a big day. Really excited for what we're launching at Netlify, but that's not what today is about.
Today is about databases. And building cool experiences with those databases. So chat, who here has tried PlanetScale? Anybody actually given it a spin? And while y'all are thinking, I'm going to -- okay. Yeah, Alan has done a little bit of PlanetScale. We've got at least one episode on PlanetScale here.
Yeah, here we go. Here we go. Here's a whole collection that currently just has our one episode in it, where Taylor from the PlanetScale team came and taught us how to set them up. And today is going to be evolving on that. All right. Yeah, yeah, yeah, a few people. Sasicodes. A couple people considering it. Jacob, on the to-do list. Yeah, Chris and the Rust adventures, for folks curious about Rust Adventure, you can go check that out if you want to learn about Rust. That's a great tool.
Yeah, let's see. You know what, I'm not going to -- we're not going to waste any time. We're going to jump right into this because I think it's a really exciting episode, and I want to have a lot of time. So let's jump over into solo programming. And what I'm going to do is first and foremost, I'm going to give a shout out to our captioning. We have Rachel here with us today taking down all these words. Thank you very much, Rachel, from White Coat Captioning. And that's made possible through the support of our sponsors, Netlify, Nx, and New Relic, all kicking in to make this show more accessible to more people, which I very much appreciate.
And we are talking today about PlanetScale. Let me get PlanetScale -- is it dot-com? It is. So here's PlanetScale. And let's get that. (Laughter) amdev, yes, it is shiny objects. Here's the thing I will say. I want people to understand there are a lot of things moving in the front-end landscape, in the web development landscape. It can cause a lot of FOMO.
Here's what I'll say. We're seeing a couple macro shifts that if you understand the macro shift, you can be comfortable not having to try every single tool. Because they're all working toward a similar set of pain points, and you can then, when you have one of those pain points, start assessing tools within the shift rather than having to try each one, right. So there are a few things that are happening right now. We had a big shift a few years back toward pre-compile everything and ship only static assets. This was due to limitations in what was out there. We had CDNs, and that was roughly it, right. Otherwise, you were managing and scaling servers. There was a lot of overhead to this.
People were getting big AWS bills or managing something like Digital Ocean or something like that, all of which are great services. But when you're running a website, it's not the most pleasant thing to do, to have to -- well, I want to update my front end. Well, let me SSH into this server that I manage and pull the git changes and rebuild and restart the site. That's not really a fun way to operate.
So instead, what we would prefer to do is push everything to git and get it compiled to a static asset. So that was a thing we were doing. That was the Jamstack. But the idea of the Jamstack was getting away from the coupling to a server where it doesn't require you to manage with Kubernetes or whatever. Then things started getting introduced.
So we have this serverless and edge-based thing. This is the first macro shift. Serverless and edge. We've seen serverless get more capable. We've got multiregion. We've got faster cold starts. We've got things like on Netlify background functions and scheduled functions. A lot of capabilities that make serverless for a lot of -- a large subset of server-based applications. Serverless can actually fill in and eliminate the need for those.
And because with services like Netlify and others you can create a folder, put your serverless functions in there, and just deploy it automatically whenever you push to git without having to configure the routing, the proxying, the DNS, the API gateways, all those things you'd have to configure if you were managing this personally, it's now way more approachable.
So edge functions are a similar idea. We'll get a little bit more into the subtleties of that. But the general idea is that serverless functions happen at a data center. And edge functions happen at the actual edge, your CDN nodes, which gives you the ability to do very, very fast things right next to the user who's requesting it.
There's also a different capability in terms of execution times and so on. We'll talk a little bit about that. But the detail doesn't matter here. It's the macro trend we're looking at.
So we've got this ability to do tiny bits of compute using JavaScript or you can use other languages, but we'll still with JavaScript because we're talking about the web experience. So you've got this ability to do, like, serverless things. The web experience is there. You also have this other macro shift of every single tool is moving to an API-first approach.
WordPress has gone headless. Most new tools get built headless. They don't even bother trying to give you a UI. They give you APIs you then hook into whatever modern stack you want and build your own web experience for it. So that's the second macro shift, API-first economy. Now, within that, there's subsets. There's the CMS style.
There's the commerce style. Et cetera. Really, what you're getting into is a specialized tool for managing a certain type of data or a certain type of transaction in the case of, like, commerce. You then get APIs to interact with that service on your web layer, and you can do that securely through serverless functions, or for things that don't need to be secure, you can do it through client-side JavaScript. So that's a second shift.
First shift is we have the ability to do work in serverless functions, edge functions that lets us make things more dynamic. So now we don't have to do only pre-compiled assets. We can do dynamic things but still don't have to manage servers. We're putting it all in git, push to git, it goes live. Second thing, blank as a service. Everything has gone API first. The whole economy is API driven. Now you go out, you choose your best-in-class tools, assemble them together, use your custom front-end framework and build a great experience that is 90% powered by blank as a service or your own custom APIs. But it's still completely custom to your needs. You spend all your time building value instead of reinventing wheels that Shopify or Contentful or WordPress has built for you.
Third macro shift then is probably the piece that's most exciting, which is the fact that databases are becoming front-end native. So databases have always been like the missing link in the way that people build for the web because you can only go so far back before you run into a thing where you need a custom database. And when you need that custom database, you kind of lose your ability, or you did previously, to be just a front-end developer. Now you're a DB admin. You had to figure out how to provision it, even if that just meant logging into AWS or Google Cloud and provisioning a Postgres database or something like that. Or you were using something like Firebase, which is more of a JavaScript SDK.
Now, it is a database, right, but it has a whole ethos around it. You're buying into a full tool. It wasn't like, here's a database and I would like to use this with whatever SDK I want. It was always like, okay, you're going to go Firebase, you're all in on Firebase.
So there's this new interesting movement where databases are starting to become serverless native. They're looking at the web development landscape and saying, oh, we should be in this serverless space. So you've got the PlanetScale kind of serverless first. You have Fauna. You've got Hasura. You've got all these different tools that solve different problems in different ways, but ultimately what they're trying to do is take databases and move them close to the people building the web experiences and to the users requesting those things.
So three macro trend, right. Dynamic experiences are possible through a git-based workflow with serverless and edge functions. We've got the whole world is moving to an API-first economy. Then we've got databases moving closer to the web experience, all of which results again in us as what would traditionally be called front-end developers being the HTML CSS JavaScript experts. Those are the three things we know.
Everybody is built toward us. So now we are full stack because we don't have to build the back ends. They're all built for us. The databases are managed by experts at PlanetScale so we don't have to figure out how to scale or deploy or manage or roll back or all these things. They built those controls for us. We don't have to become server experts because Netlify has the git-based workflow and instant rollbacks and global CDN and all the serverless deployment and DNS configuration proxies, et cetera. All those pieces that previously would have required us to learn huge amounts of additional skill sets have all been now scoped down to where I need to understand what value I want to build and the tools take care of all the boilerplate that just needs to be done well.
So that's the magic of what we're up against here. And it opens this whole new door for what we can do as developers. So that's kind of the ultra-high end here of what -- of like why you shouldn't be stressed out about the landscape, I think. So don't feel FOMO. We've got big macro trends. Those macro trends all are -- if you're aware of those and you're starting to solve problems, you can look into the specific macro trend and start to kind of dig into whether or not it's something you need to -- like do you need that tool, do you have a pain point that brings us away from the tools you already have. If so, great. Lots of things to explore. If not, it's okay. We know what the macro trends are. We are meeting those needs. And if we find that we're not being served the way that we wanted to, lots of options out there. But not anything you have to learn or else you'll go stagnant or anything like that.
So, should we build something? Yes. We should. So here's what I want to do. I want to take a look at -- this is a post that just went up on the PlanetScale blog about the serverless drivers for JavaScript. I'm going in without any context here, by the way. So I believe Taylor and some folks from the PlanetScale team are in the chat. So hello, thank you. I hope I make you proud today. And what this does, this serverless driver for JavaScript, is extremely cool because -- (laughter). Yes, do we really need computers? Computers, I believe, were a mistake. All right.
So here's what we're doing. We want to store and query data in PlanetScale from environments such as all these new edge environments that are out there, including Netlify Edge Functions. So that's what we're looking at today. Then we want this global routing and connection reliability and performance, which is also wonderful.
So we want to get into this, and I'm just going to kind of dive in. I'm not going to read the whole post here, as developers tend to do. I'm pretty sure down here, there is -- yes, there is indeed a whole setup. So here's what I'm going to do. I'm going to -- let's just set up a Vite app because they're nice and fast. And we can see our changes really quickly. So I'm going to hit get started here. There's an npm create vite. So we're going to do that. And we're going to say -- let's call this PlanetScale serverless -- what are we using today? Oh, you know what I wanted to do today, actually, I wanted to do this with Next.js because I feel like a lot of people are going to be building apps with Next.js, so let's do that instead.
So I'm going to go to the docs. We want to get to the create Next app. And we're going to do this in PlanetScale Next.js Netlify edge functions. Nice compact repo name but descriptive. So we're installing Next. And that's going to get us into our piece here. So let's go into it. PlanetScale. I'm going to -- do we have git? All right. So there's our new setup. I'm going to open this up. And let's poke around in here. So we've got the readme. All right. So real basic. Public, pages, et cetera. We're going to come in here, and we'll update it to say PlanetScale, serverless driver on Next.js plus Netlify Edge Functions. We'll copy this and drop this in here. Then I'm going to just drop out everything else. Don't need a footer. We can just kind of start with a real basic piece here. Then we'll figure out what we're going to do with the rest of it.
So we don't need image. We can hold on to that. But let's go ahead and start this off. I'm using the Netlify CLI. I'm going to run Netlify dev. It's going to autodetect that I'm running Next.js. Then it'll fire up our local server here. You can also see it's already loading an edge function for us, which is pretty dope. Now we've got our basic site running here.
And let's see. Oh, Taylor is saying it's global routing of the connections, not the data yet. Good. Good call out. Is it conceptually like Prisma? No, so this is going to be way different than Prisma because Prisma is like an SDK that takes your database and then turns it into like a TypeScript autocompletion JavaScript SDK. PlanetScale is like how to get the database connection. So this would be maybe spiritually similar to something like connects, if you've ever used that node module. Except we use it in an edge function environment and a serverless environment, which is really cool. So I want to go back to my code here. I'm going to -- let's see.
Let's take this and make it smaller. Let's take this and move it over here. I'm going to make both of these short enough to actually show up on the window. Is that enough? It needs to be a little shorter, doesn't it? I've got to actually figure out how to size my browser appropriately so that I don't have the bottom inch cut off in OBS. But anyway, that's a problem for another day.
So what I want to do in here is I want to figure out how to actually get something set up. So let's get into what we're going to start with, which is getting everything installed. So I'm going to start by installing the PlanetScale database. So we will run one of these. And then we're going to come down here, and we have to actually set this up. Okay. So I need a database first. So let me get into my PlanetScale -- I think I did this with GitHub. About to find out. Okay.
So we've got some databases here. I'm going to create a new database. And we're going to call this one -- what do we want to do today? What do we want to store today, y'all? Let's store my favorite -- let's just call this one foods. We'll do a nice easy one. And we can put it wherever we want. We've got all these different environments. We'll keep it in US East 1 for now. Let's create it. So now we've got a database. We have a connect to your database. This is cool. I'm going to have to roll this to change. Obviously I just doxxed my database. Let me pull this off screen and actually get a real database password, now that I need to delete that. Connections. Nope, that was the wrong button. Overview. Connect. Need to get a new password. There we go. Okay.
So I have my new password. Now, I'm going to do -- I'm going to save these in environment variables. So I'm going to just set up -- let's actually just deploy the site. Then we can use the environment variables on it, right. So I've got my general setup here. I'm going to git add all. Then we've got our basic site. I'm going to git commit and we'll say -- then we got that. Then I'm going to GitHub repo create. And we're going to push the existing local repo, that's this one, and we're going to say I'm Jason -- you know, we're just going to copy/paste. We can leave that out. It's going to be a public repo. Do you want to add the remote? We'll call it origin. Would I like to push? I would. And now if I come in here, now we've got our basic repo. Right.
So -- ah, so let's go back to here and actually finish reading this post. So I need to turn this on before I do the thing. Okay. So let me go back into my PlanetScale dashboard, which I've pulled off screen. Whoops. Okay. So I'm going to go to settings. Let me pull this back over, actually. So we're going into settings. Then we have beta features. All right. We've got this serverless driver, so I'm going to enroll. Good, good. Okay. So now I'm going to go back to my overview. And now I want to connect, and I'm going to be able to hit this new password.
So I'm going to go delete my previous passwords. Actually, I think I just go here and I'm like, get out of here, go away. Yeah. So get rid of those passwords. Then when I go back here, I'm going to be able to connect again, and that'll get me a new password, which I will then use. So now that I've got this hooked up, what I can do is go into my Netlify app, I'm going to create a new site by importing an existing site. We'll go to GitHub. I don't need my Netlify authorization for this. So we'll go to the Learn With Jason account. And search for PlanetScale. Got like a million repos in here. Might take a minute. Here's our edge functions. All right. So it sees it's a Next.js site. We know that's going to work. I'm going to deploy the site.
And now I can -- we can go into, like, site details. Let's change the site name. We want it to be -- I'll just make it the same. No, it's too many. So we'll just shorten it to edge. That'll work. Okay.
Then in here, we want to -- I'm going to use something in our labs just to show everybody why this is going to look different for me. We have this scopes and deploy contexts for environment variables that's available in Netlify Labs. If you haven't tried this, it is amazing. So now that I've got that, when I come back to my accounts here, I can go to environment variables. We'll see this beta tag. Inside of it -- let me make this bigger so we can see the whole UI. We've got a whole set of details here. So I'm going to opt into the new experience. We can add a variable. And this is really cool.
So I'm going to go with PlanetScale, and I need a username. And if we wanted to, which we could potentially do later, I would be able to put this together in different contexts. So I think say in production, deploy previews, branch deploys, local dev, et cetera. We can also specify certain branches. So lots and lots of control there.
For today, because I don't want to get too bogged down, I'm going to leave it on all deploy contexts. But I'm going to turn it off for all of these things because the only time I want access to the database is in these functions. So basically, even if somebody tried to leak this in the build, now we can set it to where it wouldn't work. It won't be available. So you can't accidently expose secrets if you create them like this.
So then we've got a value, and we're going to hide that value. So there's that value. This is my username. I'm going to drop it in there and create that variable. This is another one for PlanetScale password. This is for specific scopes. Keep it in the functions. And again, we're going to hide the value. And I'm going to get -- there it is. Get my password in there. So now I've got a PlanetScale database, username, and password in here. And that solves that problem. I think that's all we need. Let's go look. I'm going to need the host as well. And my host is -- where do I find my host? Connect with PlanetScale. I want to connect with PlanetScale database, which is dope. Okay. Yeah, this is great. Actually, let me show y'all this because it's really cool.
Here I am back in, and what I've done is I went to -- I'll just try this again. I went to the connect button up here. Then it shows me the PlanetScale CLI, but I want to look at all these pieces, and I can see the PlanetScale database, which is the serverless driver. When I click this, it gives me all of my .env or app.js or whatever I need. So I'm going to copy my host here, and I'm just going to put it into the environment variable so that I don't have to remember it. I can just have it available. And we're going to call this host. Put it in specific scopes again. That one we don't need to keep secret, so I can just create the variable.
Now we've got the host, password, and username all available in our scope. If I want to use this locally now because we've got our setup, I can run Netlify Link. I'm just going to use the current remote origin. I think this will do it. If that doesn't work, I'll get the site ID. I have so many sites on Netlify. Okay. You know what, rather than waiting for that, I'm going to shortcut with what I know works. I'm going to Netlify Link and use a site ID. Now I'm hooked up. Now when I run Netlify dev, it's going to pull in my environment variables.
Now, if I wanted these to be different based on my scope, again, I can go into environment variables and I could do something like set it to be a different value for production, deploy previews, local dev, et cetera. In a real database, that's what I would do. This is something PlanetScale does really well, where they create different versions of things. But yeah, really, really nice.
So now that we have our environment variables, our dev functions, everything is doing what we want. Now we can actually try to get some data. In order for me to get some data, we need to put some data into our database. I wonder if it's going to let me -- so I have to make a deploy request. I'm going to have to get some data to put into it. So let's go to the documentation real quick and get -- getting started. Let's get workflow. Is there a CLI overview? I feel like there probably is. Here's a quick start. There we go. That's what we need.
So we're going to create a database, make a schema change, insert data, and promote database to production. That's what we want to do. Let's fly through it pretty fast here. I need to add a schema to my database. I'm not doing to do relational. We're going to do straight-up data because we're not talking about database design today. We're only going to worry about getting some data in so that we can query it out.
So I'm going to create a table, and let's design our schema here a little bit. I'll do it as a file for anybody who wants to do this later. We'll create like db schema. I want to create a table, food. We'll give it an ID. That's good. We'll give it a name. That's going to be good enough because that's all we really need. I'm going to leave the products out. We don't need that. And let's then -- oh, cool. We get a console right here. I'm going to go here, click on main, if I can find it. Branches, main. Promote a branch to production. Do I need to -- oh, console.
Here it is. So I'm going to go back out here, copy my table. Then I'm going to run it. Ta-da. Then I'm going to go in here and say show tables. We have a table. Nice and easy.
Then we're going to insert some values. So let's take this one, and we're going to come down here and say insert into food. Name, we're going to insert pizza. Then let's add a couple more here. We're going to add smashburgers. What are my favorite foods? Oh, chicken teriyaki. Nice, nice, nice. Let's put -- (laughter). Solid puns. Oh, yeah, sushi. I do love a good sushi. And I do love donuts. So that's a good four items. We'll put those in.
Let's go back to our console. We'll insert all these things. Oh, does it not like my -- maybe I have to do them one at a time. If I knew more about SQL, I could probably do it in one command. I'm very good at copy/pasting, and I don't need to be good at SQL to make this work. Now I have some data in here. And we can select all from food. Okay. So let's run that and see what we get. Ta-da! We got data, everybody. All right. So this is great. So now we can actually pull some of this data out and use it. That should be all we need, right. So now I can get into actually building a thing. So I want to actually go and use this. So I'm going to go up and look at the demo application because -- that's extremely cool. Okay. I need the GitHub repo, though.
So let's look at the examples. We have a Netlify example. And I'm going to look into the edge function here to see how this is done. And so something cool is going on. You see how this is called data.json.ts? There's something clever they're doing here that I actually really like. So we can look at how this is being used in a second, but to start, I want to actually get this thing breathing.
So let's go with -- I'm going to come over here. I'm going to close that DB schema because I don't need it anymore. What I do need is a new file. It's going to live in the Netlify folder and then the edge functions folder. Then we're going to call this one -- I'm going to do the same thing, actually. Food.json.ts. What I want to be able to do is get back our data. So the first thing I'm going to do is get the context from HTTPS. It you've never seen this before, we're getting -- no, don't do that. We're just downloading this from Deno. So that lets us use URL imports and this isn't cached. Oh, it's yelling at me because we never declared it. That's fine.
So then what we do is we export default function. We call it a handler. We're going to get the request, which will be a standard request object. Then context, which is a Netlify specific thing, which we imported the type for. So we can then go here. Then what I could do is -- actually, I don't know if we're going to need the request. So I'm going to skip that. We'll leave it out. What we do then want to do is -- do we need the context either? I don't know if we need the context either. We don't. We don't need anything, actually.
So we can -- I think we can just start with nothing. Let's start with nothing. And just get a good old hello world thing going on. So we're going to return a response. That response is going to be some JSON. So we'll get our JSON. And that's going to be JSON stringify. We'll say hello world. Then we will stringify that, send back a content type of application JSON. Then I like this idea of including the care set so that if we were to include, you know, a smart quote or something, it doesn't blow up the encoding. Then access control. And this is for -- why are you yelling at me? Not assignable to parameter of type. Oh, it needs to be headers. Okay. So now it's happy. But yeah, so this is pretty dang cool. So with Next.js, we could put this into middleware, if we wanted. I mean, we have options either way. And it'll work no matter how we choose to do it, whether we want to do it in Next.js or in the kind of framework agnostic Netlify way.
So for the sake of this -- but what we can do, actually, is let's get this breathing. Then we've got like 45 minutes left. Maybe we can try to do it through the Next.js middleware as well and see what we can get. Actually, you know what -- no, that won't work. Next middleware wouldn't let us return any data. I don't think. Where's their middleware? So run code before a request is completed. You can either re-write, re-direct, add a header, or set a cookie. I guess we could put it into cookies, but we couldn't re-write the response or anything to put the data in, which we could actually do here. Actually, that might be a fun thing to try. To choose a food from -- let's do that, actually.
So we won't be able to do this with Middleware, because it doesn't have enough features. But we will be able to do something using the Netlify Edge Functions that kind of adds additional capabilities to those features. So let's get back in here. We've got -- so this is our hello world. Then in order to use this, we got to create a Netlify.toml. Then inside of it, I'm going to go back to our PlanetScale data here. And if we look at the Netlify.toml, you can see here what they've done is they've basically set up one edge function. It's going to look for data.json, or in our case, food.json. And we can call this whatever we want. It doesn't have to be -- it doesn't need to be the same name. It's just for the sake of not confusing yourself later. It's nice to have some correlation between your edge functions' naming and your pathing. Then we can say food.json, and we get to omit the suffix. So no file name required.
All right. So we've got that. And then this is going to have to get stopped and restarted because we added a Netlify.toml. This time what didn't it like? No middleware found. That's okay. And it loaded our food.json. So let's go to food.json. And we get back our hello world. So this -- whoops. This is kind of the really exciting part. We were just able to very quickly kind of build a custom route.
So you could do this with a serverless function, but the thing that's interesting about this is that the serverless function would execute kind of at the data center, whereas the edge function will execute next to the user. So if you go to load this, this loads in milliseconds. You're looking at an extremely short turnaround between requesting this and actually getting the response back, no matter where you are in the world because it runs at the CDN edge, which is really, really exciting.
So the next thing we want to do is let's actually get the PlanetScale stuff in here. So I'm going to go back, look into this edge function. I need to import this connection string here. And this is going to be -- we're using Unpackage so it pulls in the PlanetScale database. If you're paying attention to Deno news, which you don't have to be, don't feel bad, but Deno is going to support Node.js -- let's see. There was a whole thing about this. Pretty sure you can just import Node packages now. Yeah, check this out. You can do a Node thing. You also don't have to use the URL thing if you don't want to. Not a necessity. But yeah, those are going to be pretty dope. So let me look. I see mayank has just posted up a link. Let me take a look. Edge API routes, edge runtime. Does that mean we can do anything? Build high-performance APIs. Seems like that maybe does what we want. High performance. Can you do -- okay. So actually, this might work. This might work.
So yeah, we can maybe play with that. Let's get this breathing, though. We've got our connection string here. And we want -- where was it? Oh, no, I'm in the wrong -- am I in the right place? Here we go. All right. So we just connect, then the config is to get our host username and password. Then we run this connect config. So let's look how it's done in Deno.
Again, here's our set. Oh, and you can just run the whole URL, which is interesting, which we are not going to do, I don't think. Instead, we will use the username. Do I need to get a different -- wait. Wait a minute. Host username and password. If I go in with a host and say Deno -- nope. Say PlanetScale host. Then I do username, password, and go in here and go username, not in Spongebob caps. Then password. What are you unhappy about? Cannot find the name Deno. I feel like I may need to install something to get Deno happy in VS Code. Oh, yeah, there's a helper for this, actually. I think it's called templates or something.
I want recipes. I think this is it. We can list them all. And that's what I want. So we run Netlify recipes VS Code. And this should give me the configuration I need for Deno to be happier. Has no await. We will await. We shall. You're just unhappy about everything now, huh? Okay. So now that I have my connection string, I can go if here, and we can do a connection.execute. So const. Oh, you can just do multiple at once? Okay. So I'm just going to do food. It's going to be await conn.execute. And we're going to feed it select all from food. What are you unhappy about? Query, yes. What don't you like? Expected two arguments but got one. And if I don't have an argument, can I just pass an empty -- okay.
Then here we're going to JSON stringify food. So let's just try that and see what happens. Oops. What am I doing? Okay. There we go. Now if I go back to -- is it -- oh, one of these. This one. We get back our food. Our data. So this is our row. So we need to get into the rows. Instead of doing food like that, let's get response. Then food will be response.rows. Okay. Try again.
So now we've got our food items coming back from an edge function, and it's coming back in a way that looks like JSON with headers to be interpreted as JSON. If I go and look at this, as far as the browser is concerned, we just got back JSON data. So it doesn't care this was done by an edge function or whatever. It just thinks here's a file called food.json. That means that for us, we have a lot of capabilities here, where we could do something like, let's say that we want to only bring in, like, I don't know. Mains would be food.filter. We can say food.name does not equal. Then we would return our mains. What are you unhappy about? Boo. Now you explicitly have an any type. Try to get mad.
Now we have this filtered list. If we only wanted mains and not desserts, we could do it like that. But we do want all of it. So we will skip that part. Now we've got databases. Now what are you mad about? Oh, it just needed to reload. Now we have a database running at the edge. How freaking cool is that? We now have this capability, and to show you how easy this is to deploy, we can -- let's make sure I'm not adding anything we don't want to add. We've got a lock file. That's fine. We've got our edge function. We've got our .toml. We have our DB schema. Then we've got this VS Code settings, which will keep the project running the way we want. Cool. All right. Good. So we're going to git commit and say get DB running at the edge. So let's push. Now here, if we go to our deploys, it's building. And while we're waiting for it to build, in fact, why don't we -- why aren't you starting? Have y'all noticed the internet has been weird the last few days? I was having trouble on Twitter earlier. It wasn't loading things. Then my email was janky. People haven't been able to get into Zoom calls today. Just feels like the internet has been like, woof. That whole internet thing. Maybe it was a mistake.
All right. Here we go. The internet is always weird. That's fair. So, okay. We're running our build. Off we go. Static pages. All the custom routes. Get our functions out there. Get our edge functions out there. And the cache, getting deployed. So then we end up with -- all right. There's our site. If we come back out here -- are you done? There we go. Now it's live. Just had to look at it. Oh, yeah. Internet is definitely being weird. Oh, that's a fun thing to see on stream. Okay. So here's our running site. If I go to food.json, we're making live queries to a database at the freaking edge, y'all.
So here's what's cool about this. Actually, let me go into an incognito window to try this so none of my browser extensions affect this. But check this out. We are making these requests, and they take like no time. You know, 111 milliseconds. It's just very, very nice to see how quickly these run. Y'all should check this out too. Hit this and try it. Because it's just very, like, yeah. Okay.
American2050 has a good question. What's the point of separating between serverless and edge? Why not have hosts just automatically treat all serverless as edge if there's no cons on using them? The major difference is that the primary use case of edge functions is -- like, you want to be able to make a choice. Because if all of your data is back at US East 1 and you have a heavy read/write operation, so you're using, let's say, Postgres on AWS, and you need to run a serverless function that's going to read something from the database, take some user input, make changes, and then write back to the database. If you are using an edge function, you're actually doing a full hop between the user's edge node and US East 1 for each one of those writes, which will make the whole thing slower.
So if you know your data is geolocated, then you want your serverless function to be in that same data center or near it because then what happens is you get those really, really fast, like, your database is in US East 1, your serverless function is US East 1, so it's five to ten mill seconds for them to talk back and forth, and you have that one hop as the response. If you're doing something like PlanetScale has done here, where you have the ability to do portals where you can put your database read access around different places on the globe, then you would theoretically want your edge function and your database access, because they're both at the edge, you can put them there because they're nice and fast.
A lot of what we end up doing is we actually want to do, say, transformations, where you can do HTML re-writes or other kind of transformations on this software, where I want to be able to make a -- like, intercept the request and do something to it. That's kind of the primary use case for edge functions. More of the I need to check what the headers say and make a slight adjustment. Or I want to check the geolocation and make a slight adjustment.
So that ends up being a really strong use case for edge functions, whereas serverless functions are kind of more like I need a little bit of server functionality. A lot of times that's going to be coupled with a platforms a a service, database as a service, that has some component that's probably geo bound because the vast majority of services have their primary location at one of the main data centers. Let's be honest, it's almost always US East 1. So if you know you're working with one of those services, then putting your service in US East 1 is going to give you a fast processing time. So it's about trade-off. What are you doing? What's the intent? Is it faster for that to be near your user or near the data the user is accessing? And as we're seeing with tools like PlanetScale, we're not having to make that trade-off as often. So I think in the future, to answer your question more succinctly, in the future we won't differentiate because we'll be able to make those calls intelligently. But for now, you have to. Kind of weigh the impact of how you would be traversing the network to get something done. So, let's see. If I change my host to AWS connect -- oh, okay. We got bonus tips coming in here. So I'm going to change my host. Let me pull this over to the side so we still have it for testing. I'm going to go to my site settings and environment variables. Then let's update this. I want to edit it. And this is the host, right.
So right now it's US East. I'm going to do this broader one. Let's give it a shot. Okay. Then we're going to come back out here. Let's trigger a deploy to get those new environment variables out there. And now we watch it build and I dance. Okay. So this'll take a minute. I want to look and see if there's anything else we should play with here. Taylor, you're in the chat. Is there anything that I should look at that we haven't tried yet? I think you got that command backwards, Jacob. I think it's please hold. (Hold music playing)
Okay. So that's built. Now let's give it another run. The times are about the same for me, but that's not super surprising. But yeah, around 100 milliseconds. And yeah, you can do all sorts of cool stuff. But yes, I think what Taylor is saying is we can use relational databases in edge functions now, which was absolutely not really the case before. So this is freaking cool. And you can just kind of see that, like, this is not the sort of thing we were able to do previously. Like, we would have had to do all sorts of specialty stuff and get into some mess. It would have been hard. It would have required more than I probably would have been willing to deal with. So I would have just said, you know what, we're not ready for that yet. Now I don't have to make that trade-off. I don't have to know things, I just have to use this. That, I think, is sort of the joy and power of a lot of this stuff.
But yeah, what a really, really powerful thing to do. So we've got about 20 minutes left. I want to see if we can actually use this data to modify the homepage. So was it mayank that was sharing the edge functions -- or the middleware stuff? I want to do more on that later. I want to dig in and do a whole thing on Next.js middleware. We'll schedule that. We'll do a whole episode. Because I have a lot of cool things that it can do, a lot of things we want to experiment with, and we won't have time to do that in 20 minutes. So yeah, Dhanush, this stream has changed a lot. It's evolved. Is that -- evolved feels like the charitable way to describe the stream. Yeah, it's evolved. (Laughter).
Okay. So here's what I want to do. I'm going to come out here and say Jason's favorite food is -- and I'm going to say something gross. What is something gross? And I'm going to do it with something like this. Food, and we'll say a sous vide burger. Gross. So what I want to do is we can just come in here and mess with this a little bit. How does it had look on the homepage? If I go back to my homepage, let's run a Netlify dev. Durian. Yeah, that is actually pretty terrible. (Laughter)
So here we have this little piece. I want to update this on the fly, at the edge, to choose one of these other foods. So the way that I'm going to do that is let's write a new function. And I'm going to -- we'll call this one, let's see, correct food choices.ts. I'm going to drop this in here. And with this one, we're going to do a little bit more. So I still don't need the request, but it needs to be declared so this underscore causes the linting to not yell at me. Then I'm going to get this context, and I need to get that context from import. We can do the type. Context from HTTPS. And I think was edge.Netlify.com. Let me double check. That is right. Okay. So I've got my context coming from edge.Netlify.com. And I can now change the way that things are going to work a little bit. So what I want to do is I actually want to get the response. Then I'm going to do an HTML re-writer check on it. So I'm going to use a cheat sheet because we're a little short on time, and I don't want to find myself in that situation where we don't get the thing done.
So I'm going to look at Jason.af because I've built one of these. On my site right now, if you go to the uses page, a few of these, like this arc scan, is listed on Amazon.com. So if you are not in the U.S. and you go to this page and you hover over the more details of the arc scan, it should localize to your local Amazon TLD. And that's through a re-writer. So I'm going to kind of follow the model here of getting this re-writer. Then I'm going to skip down to the part that I actually need. I need the response. So the last way this works is in here, we get the response is going to be from awaiting context.next. If you think about -- if you've ever used express, you might know what a Next function does. You're putting links in a chain, right.
So when you make a request to a website that has edge functions, I make a request, and what I'm requesting is a web page. But before I get to that web page, the edge function will get the request that I've made, and it can see, you know, what are the headers that I sent, did I send any cookies along. Then I can make choices as the edge function developer to say you don't have an authorization cookie, so I'm going to redirect you somewhere else. Or to say, like, hey, you requested this page, but I want to change what it does. So when I run this context.next, I'm getting the response, like what's going to be sent back to the user, and storing it in this variable, which means that I can do some really, really cool stuff. So instead of returning a response like this, I can return an HTML re-writer.
And that is going to let me look for a certain query selector. So what I'm going to select is our food, right. Then what I want to do, I actually am now worried that this isn't going to work because we would need to transform both the JSON of this, because Next is going to send page props. So this is going to require something a little more intense. But let's try it and see what happens.
So on the element, we're going to get an element. Then inside of that, I can do something like element. -- is it replace? I think so. I think that's the one that's going to -- yeah, it's going to replace the food. And you know what, that's not actually what I want to do. I want to just change the entire contents. And I'm going to set inner content to be -- now I'll just set it to be any one of the foods. We'll just make it the name. That'll prove whether or not the thing we want to happen is happening.
Then to actually make this run, because we're not doing it yet, we have to transform on the response. Oh, and I have too many duplicate things. So I have my data, then the actual HTTP response. This is going to correct our food choices. Amazon.be might not exist, actually. Where is -- did I close this? I don't know. Oh, here it is. No, it doesn't look like. If you're not in one of these countries, it won't localize for you.
But okay. Okay. Okay. So let's give this a shot. Let's see what happens. I need -- oh, wait. I need to do something with this. So this is built, but we haven't told it where to run. So I'm going to run it on edge functions. For now, let's run it on the homepage. Like I said, I think this might not do what I want because it's not going to get the JSON sent by Next.js. That is a challenging thing to update. We would need to -- funk.function is not a function. It is a function. Did I screw something up? Export default, async function handler. I did the thing. Not a function. You are a function. Don't you lie to me. Does it show me which one failed?
Nope. So I'm going to stop and restart just in case I did something wrong here. I'm sure I've typoed something. And I just don't know what it is. Yeah, so this is the piece I was worried about. So the text content does not match server rendered HTML. And that text content lives in, like, Next data. So what I could look at -- page props, page query. How does one replace these things? Maybe I can do it if I try to replace everywhere. Let's just see. Let's try everything and see if that'll work. My guess is it won't. You can't do it like that. Got to do one of those. And I killed it, so we'll start it again. Path must be a valid path. So you can't just give it a star. You got to give it a slash star. Okay. And it -- yeah, got to do that replacement in the whole thing. So this is that hydration stuff. This is where SSR gets really hard. You want to do something like this, and now we get to figure out how Next.js works. And try to untangle that, figure out where the hydration is happening and stuff like that. So it just kind of makes for a fairly challenging process.
So what we'll instead is let's build ourselves a quick public, and we're going to go with a foods.html. Because with this, we can do basically the same thing, but I can put it -- skip this one. Come out to foods, drop it in here, and all of these become class. Then these aren't going to actually have styles. So we can I guess just leave them out. So then if we come out here, do one of these, bada-bing -- whoops. Okay. How about you. Then if I go to food.html, it didn't show up because I didn't copy it or because Next took over? It's going to fight me on any public pages. Yikes, okay. Well, that's a bummer. Well, that's no fun. I thought we'd be able to do something fun, but Next has other ideas. Well, why don't you work? Does the favicon work? That works. I just want to have a plain old HTML page. Place it in your public folder. Oh, you've got to be kidding me. Oof. Whatever, we got five minutes. Let's make it happen.
So we're going to create an API. Let's just update this one. And we're going to get the file name of foods. Then we will go into the Next config. And we're going to do a re-write and just hope that works. Destination is going to be hello. I'm assuming that works. Restart the server, theoretically we'll get our food. What are you doing? Last refresh had to perform a full reload. Oh, it's foods. Foods. I'm going to the wrong page. Oh, no. Would this have just worked if I'd done it right from the get go? Experiment. Whoops. Test.html. Augh, so that would have worked. I didn't need any of that stuff. Okay. That's going to go down to user error because I am a doofus.
So let's get this out of there. Let's get this out of there. We don't need it. And go back here, load. We're going to go back here. Look at that. It worked. Okay. So this is really cool. Let me fix the mark-up part. Okay. So it's replacing sous vide with another food. Then if we come in here and add another one, we can do, like -- random index. We'll do a math random, food times length. That should give us a random. Then when we come in here, we'll get a different favorite food every time we reload the page. So let's add a little linky. And this is going to yell because this is like that. Take a deep breath. Food.html. Come see my favorite foods. Is that going to work? You good, you good? Okay. So let's go to here.
There's our link. What? Why did you not work before and you work now? Don't be like this. Be better than this. No, it's foods. Oh, my goodness gracious. What have I done? Oh, geez. Okay. I'm a doofus. Here we go. All right. See, check that out. So we'll commit it. We're going to git commit. Let's get this thing live. And we're going to say dynamic -- we're going to call this personalization from planet scale using edge functions. Bam. Okay. So we'll take that live.
JavaScript dragon. Oh, my goodness. Yeah, (laughter). Nobody -- just don't tell anybody I did that. Okay. So we can come back up here. We can look at our deploys. This is automatically building because we pushed. And while we're looking at that, I'm going to do a quick round of shout outs. Thank you again to Rachel from White Coat Captioning, who has been doing the live captioning all day today. Thank you for being here. That's made possible by our sponsors, Netlify, Nx, New Relic, all kicking in to make the show more accessible to more people, which I really appreciate.
While you're checking out things on the site, go and look at the schedule. Oh, oh, oh! I have a thing. I have a thing. Good reminder. Taylor, thank you very much. For everybody who is watching, we have big old bonuses for everybody. I have a link for a free hat. So the first ten people -- I'm going to say this before I share the link. The first ten people who open up and fill this link out are going to get a free hat. So this is the link. That is going to be your hat. So click now. Get a hat. And if you are not one of the first ten people to do so, I apologize. But them's the bricks. Anyway, go get a hat. I'm not going to claim a hat so y'all can have one of these hats. But they're very fun. I love the -- you get the dad cap thing going on. Always good. Always good. Adjustable. So if you got a big old noggin like mine, it'll still fit your head.
Make sure you add the schedule on Google Calendar. Follow on Twitch. You can subscribe on YouTube. Any of those things both feed my ego and guarantee that you will be notified of new episodes of Learn With Jason, which I think I consider that a win-win. So if we then go back out here to our live site, which is where? Where is our live site? Is it this one? Here it is. Okay. So then we can come back out here. Here is our deployed site. Go to our favorite foods. And again, there are those dynamically loading from a database favorite foods right there on the old interwebs. Amazing.
So y'all, thank you so much for hanging out. Make sure to go check out the demo here. Remember you can find all of the source code for what we built today on GitHub right here as well. Make sure that you go check out this PlanetScale stuff. It's very cool. There's a lot going on. There's a lot to like about this. And you are, I hope, going to feel like a real capable web developer. Again, we're not front end anymore. We're full stack. It's a whole web experience. You can build a lot. You're capable of a lot. I am very excited to see what y'all are able to go out and build when you use this. And you're going to look great doing it in your brand new hat. So thanks, y'all. We'll see you next time.