NextJS Examples | Express

NextJS Examples | Starter

NextJS Examples | Layout

NextJS Examples | Express

NextJS Examples | MongoDB

In this post, you will see how to configure the NextJS starter project with an Express app.


At the root of your NextJS project, create a server.js file. This will be the entry point for your app.

Following is an example Express configuration defined in the server.js file...

const express     = require('express')
const next        = require('next')
const bodyParser  = require('body-parser')
const posts       = require('./api/post')

//next.js configuration
const dev = process.env.NODE_DEV !== 'production'
const nextApp = next({ dev })
const handle = nextApp.getRequestHandler()

nextApp.prepare().then(() => {
  const app = express()
  app.use(bodyParser.json())
  app.use(bodyParser.urlencoded({ extended: true }))
  app.use('/posts', posts)

  //catch-all for nextJS /pages
  app.get('*', (req, res) => {
    return handle(req, res)
  })
  app.listen(process.env.PORT, err => {
    if (err) throw err
    console.log('listening on port ' + process.env.port)
  })
})

Notice how we first define a NextJS instance...

const nextApp = next({ dev })

We pass in a single option for dev which specifies to run NextJS in development mode.

We then call prepare() on our instance. This method "prepares" the NextJS server with configuration options for dev environment, directory, configuration etc.

In this example, all we've passed is the dev flag which tells the NextJS server to run in development mode if process.env.NODE_DEV !== 'production'.

Notice how we create our app after nextApp.prepare() resolves. From here, we can set up our Express server for different API routes defined outside of Next.

Notice how we declare a "catch all" route...

app.get('*', (req, res) => {
  return handle(req, res)
})

Express forwards request to Next via the request handler..

const handle = nextApp.getRequestHandler()

By calling handle(req, res), we forward any request not defined through Express to NextJS.

From here, the routes defined in pages/ are applied and Next "takes over" the request if not explicitly defined somewhere else by Express.

You can even "forward" requests to the NextJS routing system directly inside an Express route...

app.get('/post', (req, res) => {
  return nextApp.render(req, res, '/post')
})

Using render() will "forward" the request to a pages/post.js file.

Updating package.json

You must update the run scripts to point to the new server.js file...

"scripts": {
  "dev": "node server.js",
  "test": "jest",
  "build": "next build",
  "start": "NODE_ENV=production node server.js -p $PORT"
}

Notice how both the devand start script have been updated to point to our server.js file.

This allows us to deploy the application as an Express app using NextJS. If we don't update these scripts then NextJS will run using the default next start script.

Your thoughts?

|

It's important to note that in theory you should never have to do this. The whole point of Nextjs is to abstract away the need to set express server up.


Remember that nextjs uses express under the hood already. When you use NextJs you are running a server. This is what allows you to do server side rendering with nextjs for example...


Using the file based routing system to create /api and /pages is how you completely avoid needing to externalize express server.

|

Great example of NextJs using Express. While the use case for setting up your NextJs project this way isn't usually necessary, it can be beneficial.


For example, to test our AWS deploy we had to add additional logging from UI server. By setting up express in this way we were easily able to log custom messages server side ...

|

Ideally nextjs is simple a UI server. It will use Express by default but if you want to build out more sophisticated backend infrastructure then building out NodeJs microservices that independently run and scale is the best move.


for example, you would have a UI server making API requests to a separate NodeJs server

|

Great read. Thx.