Huy's Notes
Notes on Deploying Next.js to Heroku

Notes on Deploying Next.js to Heroku

#deployment #heroku #javascript

Next.js is a great solution for writing React SSR applications, when it comes to deploying, there's something that worth noted.


By default, a Next.js application will be started at port :3000, and we usually have this config in package.json even for deploying:

"scripts": {
   "start": "next start"

On Heroku, we don't know which port is assigned for the application, we use the $PORT environment variable instead. So, for deployment, you'll need to let Next.js know this as well with the -p parameter, if not, the app will still running at port :3000 and will be unaccessible.

"scripts": {
   "start": "next start -p $PORT"

Next.js Config

Another thing that need to be noticed during deployment is the next.config.js file.

For some people, they don't care about the need of checking for production environment in this file, it's actually has some problem with it. For example, you have this config when you want to do add some extra logic to the build process, mostly during development:

// next.config.js
const withTypescript = require("@zeit/next-typescript")
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = withTypescript({
  webpack(config, options) {
    // Add type checking for TS
    if (options.isServer) config.plugins.push(new ForkTsCheckerWebpackPlugin())
    return config

With this config, you'll just doing fine in development environment, but on production server, you'll run into problems. One of the problems is, there's no Webpack, so the config will be failed to initialize, and your application will failed to start.

To fix this problem, we'll need to check for production environment and skip the extra development logic:

      process.env.NODE_ENV === 'development'
      ? {}
      : !process.env.NOW_REGION
      ? require('next/constants')
      : require('next-server/constants');

module.exports = (phase, { defaultConfig }) => {
    if (phase === PHASE_PRODUCTION_SERVER) {
        // Skip development logic on production
        return {};
    // Development logic
    const withTypescript = require('@zeit/next-typescript');
    const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
    return withTypescript({
        webpack(config, options) {
            if (options.isServer) config.plugins.push(new ForkTsCheckerWebpackPlugin());
            return config;

Referred in

If you think this note resonated, be it positive or negative, please feel free to send me an email and we can talk.