Loading video player...
Is there a way to build extremely fast and type- safe NexJS APIs in the newest NexJS16 and still be able to deploy them to popular providers like Versel? Turns out, yes, and it's called Elysia. I'm genuinely surprised that not more people are talking about this. Elysia is an underdog. It's not venturebacked. It's small. It's communitydriven. It's completely open source and it's really, really good. Now what is Elysiajs and how does it help us build fast good APIs
like in XJS? Well, Elysia is just a framework. That's kind of it. It's a very very good one at that very fast but at the bottom or at the the core it's just a framework right just like Huno for example. It's kind of the same thing. Hono is a web application framework. I discovered it like a year ago and it's awesome. It lets us define a backend like this with app.get get the path and then how we respond to the request. It's really straightforward and also hodos type safe. Elysia is that but
on crack because it uses bun a venturebacked runtime. So Elysia is the first big framework that uses bun by default and the most APIs that bun provides by default. Now why does this matter? because spun a venturebacked runtime and package manager and a bunch of other stuff is really fast and that's part of why Elysia can handle so many requests per second because it uses a lot of the native bun APIs. Here's a bun comparison for example. If we compare an ExpressJS hello world, right, the very
basic example, bun is by far by far faster than Node.js, probably the most used runtime to run JavaScript, right? more so than Dino even. It's really, really quick. The goal of Elysia is to leverage that into a framework and that's a very new concept that's working really well for them. Combine that with the API that looks a lot like Huno right here, a new Elysia. So, we create a app for example and then we can add individual HTTP paths, right? like the homepage where we send back hello world,
a image page where we send back a file or even stream in real time, connect websockets to enable real-time communication, right? It's a very fast runtime with a very very clean developer friendly API. And the first time I heard of Elysia was about one or two weeks ago, man, when I saw this tweet right here by the creator, Salty AOM. Please give Elysia a chance. I beg you, you know, not the greatest intro if you have something really cool going for you, but anyway, it's the fastest bun native
backend framework. It has type safety to the very limit. Everything is type- safe. Prioritize on a delightful developer experience. This is honestly core part of this cuz client and server are type safe. This is a really really nice experience and basically you can deploy anywhere you want. There's a bunch of other stuff to Elysia that would be way too much like OTEL, right? Open telemetry and observability are built in. And one of the most interesting claims to me is this one.
The performance is near that level of Golang or Rust. This is how far we've come in the JS or TS ecosystem, which is pretty crazy. And this is also important, a winter TC compliance because that's what lets us deploy to Verscell, right? Winter TC is like an open standard that a bunch of companies were involved in like for example Verscell. It's an ECMA international technical committee that wants to make JavaScript runtimes interoperable. Basically a minimum API that we share
that lets us deploy to Versel Netlfy and so on very very simplified right Elysia is winter TC compliant that means we can use it for Nex.js JS natively, right? Not only that, Verscell developers just announced Elysia support is live on Versell. They give a little code example here and basically Verscell automatically detects Elysia apps and provisions optimal resources to run them efficiently because what many people don't know is that the regular way of building NexJS APIs is horrible and you
probably shouldn't use regular NexJS to build APIs. That's my take because we need a file for each piece of functionality for every feature in our app that we want to implement. If we want to get a user, update the user, we need a file, a route.ts. There's some separate functionality related to authentication. We also need a separate route.ts for that. If there's anything else, we also need a route.ts for that. And this is messy, man. This is a really, really bad way of building APIs.
Everybody starts like this when we learn XJS. So did I. But there's a much better way that many people actually don't know about and that is when a request comes in to our next app instead of sending it directly to the route handler that should handle it is proxy through one central location called a catch all route. So what we can do in nextJS that makes Elysia for example work in next is this kind of approach where a request comes in it goes through one central
endpoint and then we forward it to that route handler that should handle the actual logic for it. And with this approach, as you'll see, this is extremely convenient and type- safe. And that's exactly what Elyssia gives us. And not only is implementing Elysia really fast because, you know, it's just well documented and it's like 2 minutes of setup. It's really, really fast, right? So, there's some benchmarks here measured in requests per second from a 2023 benchmark in plain text. It scores
high, man. Like, I don't want to get into the specific numbers. Elysia is here at you know 2.5 million requests per second while Jyn which is a go HTTP framework is at around 700,000 right this is fast like really fast and it works natively with next so how does this approach this central endpoint that enables the pattern we're about to see work in next so the nextjs integration with the nextjs app router we can run elysia on nexjs routes first we create the central endpoint that I've demoed.
We're going to define an Elysia server and then export elysia.fetch as the HTT methods that we want to use. In the case of next probably just get and post. We could use others. Oftent times in reality we don't. And then Elysia will work normally as expected because of winter CG compliance. You can treat the Elysia server as a normal NEJS API route. So in functionality it is not different than any other next API but in developer experience and speed it is right and just to just to underline that
point what I did is I deployed a lambda function to demo the real world speed of Elysia right so what this looks like so we have the EU central one region which is Frankfurt in Germany where I live and I deploy two things here to test that speed a endpoint and the second is a lambda function that queries that endpoint from the same region. So on AWS Lambda, we make a request to the Elysia endpoint and then get the latency back in our Lambda to log it out and the
result is really impressive. So this is the Lambda I deployed. Here we go. Let's send that request. First one is going to be a bit slower because of Lambda cold starts. The latency here is the important part. How fast does the Elysia endpoint respond? Is this a perfect test? No, probably not. But we can get an idea of how fast this is. If we do this a couple times to ignore the cold start, you can see here around 30 milliseconds per request, right? This is cool. There are some outliers. There
were just 360 milliseconds. I think that's pretty normal, but most of the time we're around 25 or 30 milliseconds here, which is really really impressive. And getting those kind of benefits right within our next app, right? Even existing apps takes like 1 minute, man. So we can just grab this entire code and as long as we paste it in a central slugs route, we're going to be good. That's literally our API there. So as long as we create a folder under source app and then API as any regular NexJS
app would do. If we now create a catch all route called slugs, we are forwarding all API requests to this route because it's a catch all. It catches all incoming HTTP requests from anywhere and forwards them to Elysia to handle instead of the default NexJS route handlers. So as long as we create a route here, we're going to see that for every request to our API, this single route will be called. What we're essentially saying is take the request that's incoming and let Elysia handle
it. There's a route here. There's a route here. This is nothing else than creating files that correspond to HTTP verbs in regular Nex.js JS route handlers right under the source path and then responding with a new response hello next.js and then creating a export const post post under this path and then responding with the body. This is it. This is the syntax. It's a lot simpler. It's a lot faster and it's also type safe. Now Elysia is handling all our NexJS requests absolutely deployable to
Verscell. Right. And to show you that let's start up the dev server. This is the absolutely newest NexJS 16.0.5. So, this works in the newest version. Let's make a request to our NexJS API. I already tried this a second ago, but the dev server wasn't running, so I had to retake this part. And here we go. Hello, NexJS. Right, this is nothing else than any other next route handler, but a lot more convenient and a lot faster. Of course, here uh this is just local, so
the speed isn't indicative of any deployment speeds, but this is quick, man. This is well fast. And all we did is prefix our endpoint with a path API because that's the folder we put it in and created the individual routes. There's even builtin param parsing like the body for example here, right? This uses a internal schema parsing library from that we basically tell hey we're expecting an object as the body here for this API path and if we do not pass that body the request will fail with a
built-in error. Right? If we try to make a post request here, there's some data we expect which we're not passing here. So we're going to get a message expected string expected property name to be string but found undefined. And now the last step which is probably the most magical is type safety man and that's Eden, right? That's basically an extra package that allows us to get type safety on the client just like TRPC who probably pioneered this whole type safety thing, right? I'm not a huge fan
of TRPC because I think it's pretty bloated. I don't like the setup. But they pioneer type safety between front and back end, between client and server. Right? If you make a change here on the left on the server side, then we're going to get an error on the client side that we are now passing different params. Right? We are now expecting a name and we were passing a message and TypeScript now knows, hey, you actually need a name. That's what TRPC did. got a
lot of attention for it, rightfully so, because at the time it was the absolutely best package to do that. That type safety is now built into Elysia and arguably a lot more lightweight, a lot simpler. So, what we can do is just export the type of our app from the back end. And this TypeScript type contains the entire type of our Nex.js back end, everything, right? That's how our client knows which routes exist and what kind of data they input and they output. In
fact, I made a framework just like this like a year ago myself. So, I know how this works under the hood cuz I developed it myself. It's called JStack and it's pretty much the same thing. And to be honest, I think Elysia solves it in a bit better way than I did like a year ago. It also found really good adoption because this type safety is so useful. So, all we need to do is create one centralized client in our app. We import the type of our back end that knows every route, every in and output,
and we pass that type to a client factory. With that client, we can then make requests to our API. So, let's create a lib folder right here. And lib is a convention. You don't need to call it that, but it stands for library. It's a software development convention that a lot of people, myself included, like to follow. And in here, we basically prepare libraries to be used in our nextjs project. We follow this convention at work. I'm a software engineer and we also do it at work. So,
it's very common stuff. And with that API, we can now make requests anywhere in our app like API. get or api.post and this automatically knows the kind of data that we're expecting there. If we expect a name as a tstring the client knows about it now because we are passing this type the name is going to be John because we're expecting that name here on the back end. If we would expect any other data shape like for example we just expect age and that's going to be a number type then the
client here on the left side automatically knows wherever we use this in react query on a server component anywhere we get an error name does not exist in type age number so it's real time right we don't need any kind of codegen it just works right away and we now know on the client we need to pass an age of 25 for example for that type error to go away This is a really really nice way of building Nex.js APIs, right? This is immediately deployable to Verscell. So we could just stop the
entire server, run Verscell deploy. It would just work like that because I tested it earlier with that support that Verscell just added a couple of days ago. It automatically detects ELIA apps and provisions optimal resources to run them efficiently. So going back to that lambda that I made for this, as long as we don't have a cold start, this is really quick, man. And it just works natively in next and on Versel and wherever you want to deploy. So I really
enjoy working like this. I think this is a very very good way arguably much better than standard Nex.js API routes to build your next backend. Type safe, fast, you can deploy anywhere. This is not sponsored whatsoever by anyone. I just think this is really cool technology and who knows, you might just enjoy it too, man. I really hope you enjoyed this video. I'm going to see you in the next one. Until then, have a good one and bye-bye.
A few days ago, Vercel introduced official support for Elysia. It's so much nicer than writing Next API route handlers by hand 👀 -- my links twitter: https://x.com/joshtriedcoding github: https://github.com/joschan21 appreciate you for watching 🫶