384

Suppose you have a simple block of code like this:

app.get('/', function(req, res){
    res.send('Hello World');
});

This function has two parameters, req and res, which represent the request and response objects respectively.

On the other hand, there are other functions with a third parameter called next. For example, lets have a look at the following code:

app.get('/users/:id?', function(req, res, next){ // Why do we need next?
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next(); // What is this doing?
    }
});

I can't understand what the point of next() is or why its being used. In that example, if id doesn't exist, what is next actually doing?

nbro
  • 15,395
  • 32
  • 113
  • 196
Menztrual
  • 40,867
  • 12
  • 57
  • 70
  • 17
    Next simply allows the next route handler in line to handle the request. In this case, if the user id exists, it will likely use `res.send` to complete the request. If it doesn't exist, there is likely another handler that will issue an error and complete the request then. – Dominic Barnes May 22 '12 at 04:13
  • 1
    so you're saying I have an `app.post('/login',function(req,res))` after `app.get('/users',function(req,res)) ` it will call login being the next route in the app.js file by calling next()? – Menztrual May 22 '12 at 04:19
  • 4
    Basically, the next route to be run will be another one that the URL for the request matches. In this case, if another route was registered via `app.get("/users")`, then it will be run if handler above calls next. – Dominic Barnes May 22 '12 at 04:26
  • 3
    Next is basically just a callback. – Jonathan Ong Apr 28 '13 at 08:39
  • 3
    FYI, it is called `next()`, just as a convention, but it could be called literally ANYTHING possible. – KhoPhi Oct 09 '17 at 03:40

6 Answers6

313

It passes control to the next matching route. In the example you give, for instance, you might look up the user in the database if an id was given, and assign it to req.user.

Below, you could have a route like:

app.get('/users', function(req, res) {
  // check for and maybe do something with req.user
});

Since /users/123 will match the route in your example first, that will first check and find user 123; then /users can do something with the result of that.

Route middleware is a more flexible and powerful tool, though, in my opinion, since it doesn't rely on a particular URI scheme or route ordering. I'd be inclined to model the example shown like this, assuming a Users model with an async findOne():

function loadUser(req, res, next) {
  if (req.params.userId) {
    Users.findOne({ id: req.params.userId }, function(err, user) {
      if (err) {
        next(new Error("Couldn't find user: " + err));
        return;
      }

      req.user = user;
      next();
    });
  } else {
    next();
  }
}

// ...

app.get('/user/:userId', loadUser, function(req, res) {
  // do something with req.user
});

app.get('/users/:userId?', loadUser, function(req, res) {
  // if req.user was set, it's because userId was specified (and we found the user).
});

// Pretend there's a "loadItem()" which operates similarly, but with itemId.
app.get('/item/:itemId/addTo/:userId', loadItem, loadUser, function(req, res) {
  req.user.items.append(req.item.name);
});

Being able to control flow like this is pretty handy. You might want to have certain pages only be available to users with an admin flag:

/**
 * Only allows the page to be accessed if the user is an admin.
 * Requires use of `loadUser` middleware.
 */
function requireAdmin(req, res, next) {
  if (!req.user || !req.user.admin) {
    next(new Error("Permission denied."));
    return;
  }

  next();
}

app.get('/top/secret', loadUser, requireAdmin, function(req, res) {
  res.send('blahblahblah');
});

Hope this gave you some inspiration!

Nicu Surdu
  • 8,172
  • 9
  • 68
  • 108
Asherah
  • 18,948
  • 5
  • 53
  • 72
  • You could say that! I'd be more inclined to do this kind of thing with [route middleware](http://expressjs.com/guide.html#route-middleware), though, as it doesn't couple the logic to a particular order of routes, or particular URI structures. – Asherah May 22 '12 at 04:37
  • "route middleware" link seems broken (the # suffix has no effect), can you fix? – djechlin Apr 26 '13 at 19:48
  • @djechlin: expressjs.com no longer has any documentation re: route middleware. It could be that it was removed in 3.0. I'll check. – Asherah Apr 28 '13 at 01:25
  • @djechlin: Nope; they still work, there's just no documentation any more. Typical! I'll update the post to point to the 2.x docs regarding this. – Asherah Apr 28 '13 at 01:34
  • 9
    why sometimes you return next() but sometimes don't –  Jun 09 '15 at 15:02
  • 9
    @John: the return value is actually ignored; I'm just wanting to return there to ensure I don't call `next()` again. It'd be the same if I just used `next(new Error(…)); return;`. – Asherah Jun 09 '15 at 23:47
  • Didn't quite understand the logic behind returning next(). what arguments can be given to next()? what happens to the error object? is it passed to the next middleware? – level0 May 03 '16 at 01:52
  • 4
    @level0: the return value is ignored; you can consider it shorthand for `next(new Error(…)); return;`. If we pass a value to `next`, [it's unilaterally considered an error](https://github.com/expressjs/express/blob/f3d99a4fdbe1531ea609e92c4d4ae6c269d78c7a/lib/router/route.js#L128-129). I haven't looked into the express code too much, but dig around and you'll find what you need :) – Asherah May 03 '16 at 22:33
  • 2
    @level0: (I've changed `return next(…);` to `next(…); return;` so it's less confusing.) – Asherah May 03 '16 at 22:34
  • Considering this is already an accepted answer with high ratings, perhaps you can also include an example of invoking `next('route')`? Which basically bypasses the remaining callback functions in one handler, but passes control to the next handler that has a matching route. – zedjay72 Aug 11 '16 at 13:13
  • @zedjay72: four and a half years later, I have to admit, I'm not interested. I haven't kept up with express in years. Feel free to edit the answer! – Asherah Aug 11 '16 at 23:48
  • So when you do `next(new Error("Permission denied."));`. How does express decide what to do with that? Can I pass any object to to `next()`, like `next{code: 400, text: "Page Not Found"});` ? The doc doesn't seem to describe the semantic of `next` properly! – Nawaz Jun 08 '19 at 13:37
  • @Nawaz as this question is now more than seven years old, I might suggest asking a new question or reading the source for further guidance! – Asherah Jun 10 '19 at 03:54
  • I see that `next()` takes an argument itself in your example. I wonder where does it (Error in your case) go? – jayarjo Jul 05 '19 at 04:57
  • Saying that the return value is ignored is misleading. In our middleware, we might conditionally return next() to break out of a function early, for example. It has its uses. – sammy Jul 23 '20 at 19:37
  • @sammy But the **value** returned is still ignored, whether you’re returning conditionally or not. I’m pretty sure it’s precisely the case that the return value is ignored. If you use `return 12345`, when is the value 12345 ever used? – Asherah Jul 25 '20 at 03:22
  • If return changes the program logic then it's not ignored. – sammy Jul 25 '20 at 04:27
  • @sammy I draw your attention to the word _value_. The return value is ignored and cannot change the program logic. The value `12345` in the above is ignored and cannot affect program logic. That’s a separate matter to whether the return statement is hit or not. – Asherah Jul 26 '20 at 08:12
126

I also had problem understanding next() , but this helped

var app = require("express")();

app.get("/", function(httpRequest, httpResponse, next){
    httpResponse.write("Hello");
    next(); //remove this and see what happens 
});

app.get("/", function(httpRequest, httpResponse, next){
    httpResponse.write(" World !!!");
    httpResponse.end();
});

app.listen(8080);
rajesk
  • 1,407
  • 1
  • 9
  • 8
  • 7
    Very succinct! Thanks! But how do you make sure that the first `.get` is called and not the 2nd one? – JohnnyQ Feb 28 '17 at 14:27
  • 32
    @JohnnyQ It will be top to bottom execution – Tapash Mar 14 '17 at 07:07
  • @JohnnyQ The routes are picked up in the fashion they are declared. If there are two matching routes, the one that's encountered first in the program flow will get picked. – Shubham Anand Jun 22 '20 at 02:52
  • 3
    @JohnnyQ thanks! i just needed someone, in all of the documentation i've read, to simply say "top to bottom execution." how simple! seems obvious but when you're learning this stuff nothing is obvious and that was really bothering me. – Nathaniel Hoyt Jan 13 '21 at 20:47
108

Before understanding next, you need to have a little idea of Request-Response cycle in node though not much in detail. It starts with you making an HTTP request for a particular resource and it ends when you send a response back to the user i.e. when you encounter something like res.send(‘Hello World’);

let’s have a look at a very simple example.

app.get('/hello', function (req, res, next) {
  res.send('USER')
})

Here we do not need next(), because resp.send will end the cycle and hand over the control back to the route middleware.

Now let’s take a look at another example.

app.get('/hello', function (req, res, next) {
  res.send("Hello World !!!!");
});

app.get('/hello', function (req, res, next) {
  res.send("Hello Planet !!!!");
});

Here we have 2 middleware functions for the same path. But you always gonna get the response from the first one. Because that is mounted first in the middleware stack and res.send will end the cycle.

But what if we always do not want the “Hello World !!!!” response back. For some conditions we may want the "Hello Planet !!!!" response. Let’s modify the above code and see what happens.

app.get('/hello', function (req, res, next) {
  if(some condition){
    next();
    return;
  }
  res.send("Hello World !!!!");  
});

app.get('/hello', function (req, res, next) {
  res.send("Hello Planet !!!!");
});

What’s the next doing here. And yes you might have gusses. It’s gonna skip the first middleware function if the condition is true and invoke the next middleware function and you will have the "Hello Planet !!!!" response.

So, next pass the control to the next function in the middleware stack.

What if the first middleware function does not send back any response but do execute a piece of logic and then you get the response back from second middleware function.

Something like below:-

app.get('/hello', function (req, res, next) {
  // Your piece of logic
  next();
});

app.get('/hello', function (req, res, next) {
  res.send("Hello !!!!");
});

In this case you need both the middleware functions to be invoked. So, the only way you reach the second middleware function is by calling next();

What if you do not make a call to next. Do not expect the second middleware function to get invoked automatically. After invoking the first function your request will be left hanging. The second function will never get invoked and you will not get back the response.

Mav55
  • 4,080
  • 2
  • 21
  • 20
  • So `next()` performs like a `goto` with a hard-wired label? That is, in your third snippet, once you call `next()`, `res.send("Hello World !!!!"); ` would never be executed? I noticed that @Ashe always had a `return;` after `next` calls that had code in the same execution tree... Guess I could always just check in express, huh? /runs over to his text editor ;) – ruffin May 07 '18 at 14:49
  • @ruffin yes you can think of next akin to a goto. but next knows where to go to unlike goto which requires a label. Next will pass the control to the next middleware function. Also, you can name 'next' anything you like. It's just a label here. But the best practice is to use the name 'next' – Mav55 May 07 '18 at 15:02
  • 4
    Okay, looks like that's not accurate. I tried the code ([pastebin here](https://pastebin.com/raw/eTfVZb9j)), and the code after the `next()` call *is called*. In this case, `past the next() call` is written to the console, and then I get a `Error: Can't set headers after they are sent.` error, as the second `res.send` is called, though unsuccessfully. The code flow **does return** after the `next()` call, which makes @Ashe's `returns` (or other logic management) important. – ruffin May 07 '18 at 15:13
  • 7
    @ruffin, yeah you are right. We need a return statement after the `next()` to skip the execution of the remaining statements. thanks for pointing out that. – Mav55 May 07 '18 at 18:33
  • one more question... is next() basically a synonym of the often used "done()" ? is it the same? – MMMM Oct 11 '18 at 07:52
  • 3
    Thank you for actually explaining what "middleware" is/does w/clear examples and not just parroting the documentation. This was the only answer that actually says anything clear about what happens, why & how. – mc01 Nov 25 '19 at 05:28
  • @Mav55 Can you explain more on `Here we do not need next(), because resp.send will end the cycle and hand over the control back to the route middleware`. What is `Route middleware` here? – D_S_X Nov 15 '20 at 14:33
  • what I don't understand is why don't we just complete the logic in the first middleware itself and rely on another middleware? – mdehghani Mar 16 '22 at 11:51
20

Next is used to pass control to the next middleware function. If not the request will be left hanging or open.

4

A bit of internals here. The main purpose of express app handle function is to send a response to the client, and terminate the request-response cycle. And termination of this cycle can be done by one of the response methods (e.g. res.end(), res.json(), etc). Meaning if a middleware or route handler does some actions but then doesn't call one of the response methods or pass the control to the next handler or middleware, the request-response cycle will not be terminated. But what the next does depends on where and how it gets called.

To manage different tasks (route handlers, middlewares) express creates stacks. They look like a queue of the tasks. Each router and route creates its own stack of tasks;

The use method of the express app pushes task (middleware function) to the stack of the router. The app.get, app.post, etc creates a separate route (with its own stack, and pushes to it the actual handlers of the route) in the router, then pushes to the router wrapped in a function those route handlers. Meaning when a route gets created in the router stack something like route task (wrapper function) with subtasks pushed.

// pushes task to the router stack
app.use((req, res, next) => {
    console.log('log request');
    next();
});

// creates route, route stack, 
// pushes tasks to the route stack,
// wraps tasks in a function (another task)
// pushes wrapper function to the
// router stack
app.get('/', (req, res, next) => {
    res.send('Hello World');
});

As a route has its own stack calling next without the arguments gets us only to the next handler of the route:

app.get('/', 
    (req, res, next) => {
        console.log('first handler');
        // passes the control to the second handler
        next();
    },
    (req, res, next) => {
        console.log('second handler');
        res.send('Hello World');
    }
);

Calling next inside a middleware (express recommends to apply use method for mounting a middleware) gets us to the next route or middleware of the router, cause middleware (when mounted) was pushed to the router stack.

next accepts different arguments. Any argument that is not 'route' or 'router' will be treated as an error and will be passed to the error middleware that must be mounted after all routes and have four arguments:

// error handling middleware
app.use((error, req, res, next) => {
    res.status(error.status || 500);
    res.send(error.message || 'Server internal error');
});

String 'route' as an argument for next will skip all remaining route handlers and gets us the the next route of the router:

app.get('/', 
    (req, res, next) => {
        console.log('first handler');
        // passes control to the next route
        next('route');
    },
    (req, res, next) => {
        // this handler will be skipped
        next();
    }
);

app.get('/',
    (req, res, next) => {
        // this route will be called at the end
        res.send('Hello World');
    }
);

String 'router' as an argument for next gets us out of the current router:

// router 'one'
app.get('/', 
    (req, res, next) => {
        console.log('first handler');
        // passes control to the next router
        next('router');
    },
    (req, res, next) => {
        // this handler will be skipped
        next();
    }
);

// router 'two'
app.get('/',
    (req, res, next) => {
        // this route will be called at the end
        res.send('Hello World');
    }
);
Vadi
  • 3,279
  • 2
  • 13
  • 30
0

I also want to add why express doesn't call the next middleware and gives us control over it. Since node is asynchronous, if express calls the next middleware without waiting for some asynchronous call to finish, the response might be incomplete or contains errors, so users have control over when the next middleware function should be called.

Bharat
  • 386
  • 5
  • 20