Check out a free preview of the full Introduction to Next.js 13+, v3 course

The "Middleware" Lesson is part of the full, Introduction to Next.js 13+, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Scott explains the concept of middleware in Next.js, which allows running code before a request is completed. Middleware can modify the response by rewriting, redirecting, modifying request or response headers, or even providing a direct response based on the incoming request.


Transcript from the "Middleware" Lesson

>> All righty, let's keep it rolling then. So next up is going to be middleware. So middleware is really cool. If you ever use Express or, I don't know, any language ever, on the back end, you've heard of middleware. Best way I can describe middleware, it's just like plugins that run before your last function runs, basically, right?

If I'm driving a car and I'm trying to navigate it to the grocery store, a middleware would be everywhere I had to stop before I got there. First I gotta stop here, and then I gotta stop here, and I gotta get gas, and then there's traffic here. And then I got pulled over for speeding, and then [LAUGH] this other thing, and then now I made it to the store.

Okay, everything in between you getting to the store was middleware. And basically, what we can do with Next.js, so I told you about edge runtime, you're running on the edge, which is a CDN. Middleware is a function that runs on the edge. It basically will protect your serverless functions, or actually, your entire app, even your pages.

They won't even know someone was asking for them because the middleware will stop the the traffic first and run whatever analysis you want. You can check authentication, you can redirect, you can do all different types of things in the middleware. So let's talk about that. In order to do that, it's actually quite simple.

On a route of your repo, you just do a middleware.ts, it's pretty simple. And it's pretty much the exact same thing as a service function. You can think of it that way, it's like a service function that runs on an edge. So the syntax is mostly the same for the function itself, although there's some special stuff about when you want to match things.

Maybe you don't want the middleware to run on every single route, because maybe this middleware is only checking authentication and there are some public pages you don't want it to check. Maybe you do want it to run on every route and you wanna write that logic yourself inside the function.

There's a lot of ways to go about it, there's really not one way. The only thing you need to do is by default is just export a function that returns a response at some point, so let's do that. So we'll say export some function called middleware, that's just gonna return some response.

At one point it's gonna get a request. And I'm just gonna export default middleware. Like that, right? That's the bare minimum you need to do. In the next example, you can see this person is, I said this person, me [LAUGH], you can see that I'm just redirecting to home.

I'm just going to import NextResponse, or not NextRequest, NextResponse, there we go. In this example, I'm just making every single request that you send me, go home, no matter what. It's going to redirect every single thing, no matter if you try to go the API, if you try to go to any page.

And then what we also wanna do is just export some matchers, so where do we want this to run? So there's a million ways to do this, so I'm just gonna just pull it up in the dock so we can talk about all the ways. Cuz if you don't like regexs, then I don't know what to tell you.

[LAUGH] Because it's a lot of regexs in here, but that's what ChatGPT is for, so [LAUGH]. So basically, if you export a config object, you can put a matcher in here. I'm glad that they did make an update this time around that you don't have to use regexs now.

You can do a glob pattern to be like, yeah, I just wanna, in this case, I want to match anything that's /about/:path, anything after that path, or /dashboard/:path, which is really cool. But as you can see here, you can also return a regex that matches all requests except for the one starting with API or this.

You probably don't wanna do the regexs, especially now that you can do the matching this way. The simple way also is just do it in your code. You can honestly just do it in here. You can look at the request object and be like, if the request is this path, or I have an array of URLs that I know I wanna protect, if it's one of these, then redirect somewhere else, or do whatever you want.

You can check the headers, you can check the cookies here, you can do whatever you want here, and you can protect, redirect, rewrite. Anything a response object can do, you can do in here. So it's actually pretty cool. So yeah, I'm gonna actually get this to run though, so let's see what happens.

What happens if I do it that way? No, it just doesn't like that at all. I think that you have to do a config, let's see. Let's say matcher. And let's say /todos, what do we have? Slash, yeah, /todos/path. No, I think it's a /todo, /todos, let's see what happens on that.

/todos, yeah, you can see it went home when I tried to go /todos. I click on todos, it just stays home, it won't let me go, right? That's the intention. And it happens before the request even comes in. Yeah, any questions on that? Yes.
>> Can you distribute your middleware manually through the app and then import them into one, the root?

>> Distribute your middleware, like middleware functions is the question. I'm guessing they're asking, can I take the logic that I would have in this function and have it somewhere else and then import it? Yes, you totally can, but as far as the middleware function itself, it only lives on the root.

This is the only file other than the next.config.js that should live on the root of your project, and that's where Next.js is expecting it to be. If you put it anywhere else, I don't think it'll work.
>> Does file streaming work the same in the API directory?
>> File streaming, does file streaming work the same in the API directory?

When I hear file streaming, I think of so many different things. I don't know if they mean a streaming response. If that's the case, no, it works entirely differently. Because the response object is completely different now and it follows a web standard, you'd have to use a iterator to be able to do something like that to stream.

Let me see if I have an example of that. No, it's not this example, this is something else. I don't even have an example in here, I would have to show you some code that I wrote for something else. If that's what they were talking about, no, it is completely different because the response object is different.

If they were talking about streaming a file, as in uploading a file to the server and streaming that, that also will be very different because it's a different request object. And how you handle that with the standard request object is way different than how you would have handled it with Next.js' request object.

So yes, anything involving something very tedious and specific as streaming is gonna be way different in that API folder than it was in the pages API folder.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now