├── .gitignore ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── components └── logo.js ├── config └── nginx.conf.erb ├── next.config.js ├── package-lock.json ├── package.json └── pages └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | dist/ 3 | node_modules/ 4 | .next/ 5 | *.log 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Mars Hall 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bin/start-nginx-static 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Next.js](https://nextjs.org/) on Heroku 2 | 3 | Deploy [React](https://facebook.github.io/react/)-based universal web apps on [Heroku](https://www.heroku.com/home). 4 | 5 | **Demo deployment** from this repo: 6 | https://nextjs.herokuapp.com 7 | 8 | **A custom Node/Express server** is supported. Use it to: 9 | 10 | * combine a Node API with a Next/React UI 11 | * implement custom URL routes 12 | 13 | ▶️ **[Next with custom Express server](https://github.com/mars/heroku-nextjs-custom-server-express)** 14 | 15 | ## Requires 16 | 17 | * Heroku 18 | * [command-line tools (CLI)](https://devcenter.heroku.com/articles/heroku-command-line) 19 | * [a free account](https://signup.heroku.com) 20 | * [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) 21 | * [Node.js](https://nodejs.org) 22 | * [Next.js](https://github.com/zeit/next.js) 23 | 24 | ## Production deployment 25 | 26 | Once you have a [Next app working locally](https://nextjs.org/docs/#setup), you may deploy it for public access. 27 | 28 | 1. Revise the `npm start` script to set the [web listener `$PORT`](https://devcenter.heroku.com/articles/dynos#local-environment-variables): 29 | 30 | Merge this entry into **package.json**: 31 | 32 | ```json 33 | { 34 | "scripts": { 35 | "dev": "next", 36 | "build": "next build", 37 | "start": "next start -p $PORT" 38 | } 39 | } 40 | ``` 41 | 42 | ⭐️ *In March 2019, [Heroku began running `npm run build` automatically](https://devcenter.heroku.com/changelog-items/1573), so the old `heroku-postbuild` script entry is no longer required.* 43 | 44 | 1. Ensure the app is a git repo, ignoring local-only directories: 45 | 46 | ```bash 47 | git init 48 | (echo node_modules/ && echo .next/) >> .gitignore 49 | ``` 50 | 1. Create the Heroku app: 51 | 52 | ```bash 53 | heroku create $APP_NAME 54 | ``` 55 | 1. 🚀 Deploy: 56 | 57 | ```bash 58 | git add . 59 | git commit -m 'Next.js app on Heroku' 60 | git push heroku main 61 | ``` 62 | ⭐️ *As of July 2020, [Heroku supports `git push heroku main`](https://devcenter.heroku.com/changelog-items/1829) and encourages its use. The support for the branch name of 'master' will remain available for backwards compatibility.* 63 | 64 | 1. ♻️ Deploy changes: add, commit, & push again. 65 | 66 | ## Custom Config 67 | 68 | Next itself supports build & runtime configuration through the [next.config.js](https://nextjs.org/docs/#exposing-configuration-to-the-server--client-side) file. 69 | 70 | Use environment variables ([Heroku config vars](https://devcenter.heroku.com/articles/config-vars)) within your React components, no rebuilds required! Simply set [next.config.js](https://nextjs.org/docs/#exposing-configuration-to-the-server--client-side) values from the server's environment using `process.env` object. 71 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Next.js", 3 | "description": "Universal web app built on React.js, static-served by Nginx", 4 | "scripts": { 5 | }, 6 | "env": { 7 | }, 8 | "formation": { 9 | "web": { 10 | "quantity": 1 11 | } 12 | }, 13 | "addons": [ 14 | 15 | ], 16 | "buildpacks": [ 17 | { 18 | "url": "heroku/nodejs" 19 | }, 20 | { 21 | "url": "heroku-community/nginx" 22 | } 23 | ], 24 | "stack": "heroku-22" 25 | } 26 | -------------------------------------------------------------------------------- /components/logo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | // Circle Right icon designed by Hector (CC license): https://thenounproject.com/term/circle-right/557979 4 | export default (props) => -------------------------------------------------------------------------------- /config/nginx.conf.erb: -------------------------------------------------------------------------------- 1 | daemon off; 2 | # stay attached to the dyno process, run in Procfile / web 3 | 4 | pid /app/nginx.pid; 5 | # /app is $HOME & working directory of Heroku dyno 6 | 7 | error_log stderr info; 8 | # As documented for Nginx, but we still see error during start-up in log: 9 | # > nginx: [alert] could not open error log file: open() "./logs/error.log" 10 | 11 | worker_processes <%= ENV['NGINX_WORKERS'] || 4 %>; 12 | # Heroku dynos have at least 4 cores. 13 | 14 | events { 15 | use epoll; 16 | accept_mutex on; 17 | worker_connections <%= ENV['NGINX_WORKER_CONNECTIONS'] || 1024 %>; 18 | } 19 | 20 | http { 21 | gzip on; 22 | gzip_comp_level 2; 23 | gzip_min_length 512; 24 | gzip_proxied any; # Heroku router sends Via header 25 | 26 | server_tokens off; 27 | 28 | log_format heroku_www_app 29 | '$remote_addr - $http_x_request_id [$time_iso8601] ' 30 | '"$request" $status $body_bytes_sent ' 31 | '"$http_referer" "$http_user_agent"'; 32 | access_log /dev/stdout heroku_www_app; 33 | 34 | include mime.types; 35 | default_type application/octet-stream; 36 | sendfile on; 37 | 38 | client_body_timeout <%= ENV['NGINX_CLIENT_BODY_TIMEOUT'] || 5 %>; 39 | # Must read the body in 5 seconds. 40 | 41 | server { 42 | listen <%= ENV["PORT"] %>; 43 | server_name _; 44 | keepalive_timeout 5; 45 | client_max_body_size <%= ENV['NGINX_CLIENT_MAX_BODY_SIZE'] || 1 %>M; 46 | 47 | ## HTTPS Only 48 | if ($http_x_forwarded_proto != "https") { 49 | return 301 https://$host$request_uri; 50 | } 51 | 52 | root <%= ENV["NGINX_ROOT"] || '/app/dist' %>; 53 | 54 | location / { 55 | ## Clean URLs: match on extensionless requests. 56 | # try_files $uri $uri/ $uri.html =404; 57 | 58 | ## Single-page app client-side routing: returns index.html if the requested path doesn't exist. 59 | ## When enabled, the client-side app must handle its own 404 errors. 60 | error_page 404 = /index.html; 61 | } 62 | 63 | ## Define specific behaviors for sub directories and other locations. 64 | location /_next { 65 | expires 7d; 66 | } 67 | 68 | ## Custom error pages 69 | error_page 404 /404.html; 70 | # error_page 500 /500.html; 71 | } 72 | 73 | ## Canonical Host: redirect to a canonical hostname. 74 | ## Multiple server blocks may be used, one for each hostname to redirect from. 75 | # server { 76 | # server_name some-other-name.example.com; 77 | # return 301 https://canonical-name.example.com$request_uri; 78 | # } 79 | # server { 80 | # server_name yet-another-name.example.com; 81 | # return 301 https://canonical-name.example.com$request_uri; 82 | # } 83 | # … 84 | } 85 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('next').NextConfig} 3 | */ 4 | const nextConfig = { 5 | output: 'export', 6 | // Optional: Add a trailing slash to all paths `/about` -> `/about/` 7 | // trailingSlash: true, 8 | // Optional: Change the output directory `out` -> `dist` 9 | distDir: 'dist', 10 | } 11 | 12 | module.exports = nextConfig 13 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "heroku-nextjs", 3 | "version": "2.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "heroku-nextjs", 9 | "version": "2.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "next": "^13.4.4", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "engines": { 17 | "node": "20" 18 | } 19 | }, 20 | "node_modules/@next/env": { 21 | "version": "13.4.4", 22 | "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.4.tgz", 23 | "integrity": "sha512-q/y7VZj/9YpgzDe64Zi6rY1xPizx80JjlU2BTevlajtaE3w1LqweH1gGgxou2N7hdFosXHjGrI4OUvtFXXhGLg==" 24 | }, 25 | "node_modules/@next/swc-darwin-arm64": { 26 | "version": "13.4.4", 27 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.4.tgz", 28 | "integrity": "sha512-xfjgXvp4KalNUKZMHmsFxr1Ug+aGmmO6NWP0uoh4G3WFqP/mJ1xxfww0gMOeMeSq/Jyr5k7DvoZ2Pv+XOITTtw==", 29 | "cpu": [ 30 | "arm64" 31 | ], 32 | "optional": true, 33 | "os": [ 34 | "darwin" 35 | ], 36 | "engines": { 37 | "node": ">= 10" 38 | } 39 | }, 40 | "node_modules/@next/swc-darwin-x64": { 41 | "version": "13.4.4", 42 | "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.4.tgz", 43 | "integrity": "sha512-ZY9Ti1hkIwJsxGus3nlubIkvYyB0gNOYxKrfsOrLEqD0I2iCX8D7w8v6QQZ2H+dDl6UT29oeEUdDUNGk4UEpfg==", 44 | "cpu": [ 45 | "x64" 46 | ], 47 | "optional": true, 48 | "os": [ 49 | "darwin" 50 | ], 51 | "engines": { 52 | "node": ">= 10" 53 | } 54 | }, 55 | "node_modules/@next/swc-linux-arm64-gnu": { 56 | "version": "13.4.4", 57 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.4.tgz", 58 | "integrity": "sha512-+KZnDeMShYkpkqAvGCEDeqYTRADJXc6SY1jWXz+Uo6qWQO/Jd9CoyhTJwRSxvQA16MoYzvILkGaDqirkRNctyA==", 59 | "cpu": [ 60 | "arm64" 61 | ], 62 | "optional": true, 63 | "os": [ 64 | "linux" 65 | ], 66 | "engines": { 67 | "node": ">= 10" 68 | } 69 | }, 70 | "node_modules/@next/swc-linux-arm64-musl": { 71 | "version": "13.4.4", 72 | "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.4.tgz", 73 | "integrity": "sha512-evC1twrny2XDT4uOftoubZvW3EG0zs0ZxMwEtu/dDGVRO5n5pT48S8qqEIBGBUZYu/Xx4zzpOkIxx1vpWdE+9A==", 74 | "cpu": [ 75 | "arm64" 76 | ], 77 | "optional": true, 78 | "os": [ 79 | "linux" 80 | ], 81 | "engines": { 82 | "node": ">= 10" 83 | } 84 | }, 85 | "node_modules/@next/swc-linux-x64-gnu": { 86 | "version": "13.4.4", 87 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.4.tgz", 88 | "integrity": "sha512-PX706XcCHr2FfkyhP2lpf+pX/tUvq6/ke7JYnnr0ykNdEMo+sb7cC/o91gnURh4sPYSiZJhsF2gbIqg9rciOHQ==", 89 | "cpu": [ 90 | "x64" 91 | ], 92 | "optional": true, 93 | "os": [ 94 | "linux" 95 | ], 96 | "engines": { 97 | "node": ">= 10" 98 | } 99 | }, 100 | "node_modules/@next/swc-linux-x64-musl": { 101 | "version": "13.4.4", 102 | "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.4.tgz", 103 | "integrity": "sha512-TKUUx3Ftd95JlHV6XagEnqpT204Y+IsEa3awaYIjayn0MOGjgKZMZibqarK3B1FsMSPaieJf2FEAcu9z0yT5aA==", 104 | "cpu": [ 105 | "x64" 106 | ], 107 | "optional": true, 108 | "os": [ 109 | "linux" 110 | ], 111 | "engines": { 112 | "node": ">= 10" 113 | } 114 | }, 115 | "node_modules/@next/swc-win32-arm64-msvc": { 116 | "version": "13.4.4", 117 | "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.4.tgz", 118 | "integrity": "sha512-FP8AadgSq4+HPtim7WBkCMGbhr5vh9FePXiWx9+YOdjwdQocwoCK5ZVC3OW8oh3TWth6iJ0AXJ/yQ1q1cwSZ3A==", 119 | "cpu": [ 120 | "arm64" 121 | ], 122 | "optional": true, 123 | "os": [ 124 | "win32" 125 | ], 126 | "engines": { 127 | "node": ">= 10" 128 | } 129 | }, 130 | "node_modules/@next/swc-win32-ia32-msvc": { 131 | "version": "13.4.4", 132 | "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.4.tgz", 133 | "integrity": "sha512-3WekVmtuA2MCdcAOrgrI+PuFiFURtSyyrN1I3UPtS0ckR2HtLqyqmS334Eulf15g1/bdwMteePdK363X/Y9JMg==", 134 | "cpu": [ 135 | "ia32" 136 | ], 137 | "optional": true, 138 | "os": [ 139 | "win32" 140 | ], 141 | "engines": { 142 | "node": ">= 10" 143 | } 144 | }, 145 | "node_modules/@next/swc-win32-x64-msvc": { 146 | "version": "13.4.4", 147 | "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.4.tgz", 148 | "integrity": "sha512-AHRITu/CrlQ+qzoqQtEMfaTu7GHaQ6bziQln/pVWpOYC1wU+Mq6VQQFlsDtMCnDztPZtppAXdvvbNS7pcfRzlw==", 149 | "cpu": [ 150 | "x64" 151 | ], 152 | "optional": true, 153 | "os": [ 154 | "win32" 155 | ], 156 | "engines": { 157 | "node": ">= 10" 158 | } 159 | }, 160 | "node_modules/@swc/helpers": { 161 | "version": "0.5.1", 162 | "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", 163 | "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", 164 | "dependencies": { 165 | "tslib": "^2.4.0" 166 | } 167 | }, 168 | "node_modules/busboy": { 169 | "version": "1.6.0", 170 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", 171 | "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", 172 | "dependencies": { 173 | "streamsearch": "^1.1.0" 174 | }, 175 | "engines": { 176 | "node": ">=10.16.0" 177 | } 178 | }, 179 | "node_modules/caniuse-lite": { 180 | "version": "1.0.30001497", 181 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001497.tgz", 182 | "integrity": "sha512-I4/duVK4wL6rAK/aKZl3HXB4g+lIZvaT4VLAn2rCgJ38jVLb0lv2Xug6QuqmxXFVRJMF74SPPWPJ/1Sdm3vCzw==", 183 | "funding": [ 184 | { 185 | "type": "opencollective", 186 | "url": "https://opencollective.com/browserslist" 187 | }, 188 | { 189 | "type": "tidelift", 190 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 191 | }, 192 | { 193 | "type": "github", 194 | "url": "https://github.com/sponsors/ai" 195 | } 196 | ] 197 | }, 198 | "node_modules/client-only": { 199 | "version": "0.0.1", 200 | "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", 201 | "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" 202 | }, 203 | "node_modules/js-tokens": { 204 | "version": "4.0.0", 205 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 206 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 207 | }, 208 | "node_modules/loose-envify": { 209 | "version": "1.4.0", 210 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 211 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 212 | "dependencies": { 213 | "js-tokens": "^3.0.0 || ^4.0.0" 214 | }, 215 | "bin": { 216 | "loose-envify": "cli.js" 217 | } 218 | }, 219 | "node_modules/nanoid": { 220 | "version": "3.3.6", 221 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 222 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 223 | "funding": [ 224 | { 225 | "type": "github", 226 | "url": "https://github.com/sponsors/ai" 227 | } 228 | ], 229 | "bin": { 230 | "nanoid": "bin/nanoid.cjs" 231 | }, 232 | "engines": { 233 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 234 | } 235 | }, 236 | "node_modules/next": { 237 | "version": "13.4.4", 238 | "resolved": "https://registry.npmjs.org/next/-/next-13.4.4.tgz", 239 | "integrity": "sha512-C5S0ysM0Ily9McL4Jb48nOQHT1BukOWI59uC3X/xCMlYIh9rJZCv7nzG92J6e1cOBqQbKovlpgvHWFmz4eKKEA==", 240 | "dependencies": { 241 | "@next/env": "13.4.4", 242 | "@swc/helpers": "0.5.1", 243 | "busboy": "1.6.0", 244 | "caniuse-lite": "^1.0.30001406", 245 | "postcss": "8.4.14", 246 | "styled-jsx": "5.1.1", 247 | "zod": "3.21.4" 248 | }, 249 | "bin": { 250 | "next": "dist/bin/next" 251 | }, 252 | "engines": { 253 | "node": ">=16.8.0" 254 | }, 255 | "optionalDependencies": { 256 | "@next/swc-darwin-arm64": "13.4.4", 257 | "@next/swc-darwin-x64": "13.4.4", 258 | "@next/swc-linux-arm64-gnu": "13.4.4", 259 | "@next/swc-linux-arm64-musl": "13.4.4", 260 | "@next/swc-linux-x64-gnu": "13.4.4", 261 | "@next/swc-linux-x64-musl": "13.4.4", 262 | "@next/swc-win32-arm64-msvc": "13.4.4", 263 | "@next/swc-win32-ia32-msvc": "13.4.4", 264 | "@next/swc-win32-x64-msvc": "13.4.4" 265 | }, 266 | "peerDependencies": { 267 | "@opentelemetry/api": "^1.1.0", 268 | "fibers": ">= 3.1.0", 269 | "react": "^18.2.0", 270 | "react-dom": "^18.2.0", 271 | "sass": "^1.3.0" 272 | }, 273 | "peerDependenciesMeta": { 274 | "@opentelemetry/api": { 275 | "optional": true 276 | }, 277 | "fibers": { 278 | "optional": true 279 | }, 280 | "sass": { 281 | "optional": true 282 | } 283 | } 284 | }, 285 | "node_modules/picocolors": { 286 | "version": "1.0.0", 287 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 288 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 289 | }, 290 | "node_modules/postcss": { 291 | "version": "8.4.14", 292 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", 293 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", 294 | "funding": [ 295 | { 296 | "type": "opencollective", 297 | "url": "https://opencollective.com/postcss/" 298 | }, 299 | { 300 | "type": "tidelift", 301 | "url": "https://tidelift.com/funding/github/npm/postcss" 302 | } 303 | ], 304 | "dependencies": { 305 | "nanoid": "^3.3.4", 306 | "picocolors": "^1.0.0", 307 | "source-map-js": "^1.0.2" 308 | }, 309 | "engines": { 310 | "node": "^10 || ^12 || >=14" 311 | } 312 | }, 313 | "node_modules/react": { 314 | "version": "18.2.0", 315 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", 316 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", 317 | "dependencies": { 318 | "loose-envify": "^1.1.0" 319 | }, 320 | "engines": { 321 | "node": ">=0.10.0" 322 | } 323 | }, 324 | "node_modules/react-dom": { 325 | "version": "18.2.0", 326 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", 327 | "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", 328 | "dependencies": { 329 | "loose-envify": "^1.1.0", 330 | "scheduler": "^0.23.0" 331 | }, 332 | "peerDependencies": { 333 | "react": "^18.2.0" 334 | } 335 | }, 336 | "node_modules/scheduler": { 337 | "version": "0.23.0", 338 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", 339 | "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", 340 | "dependencies": { 341 | "loose-envify": "^1.1.0" 342 | } 343 | }, 344 | "node_modules/source-map-js": { 345 | "version": "1.0.2", 346 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 347 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 348 | "engines": { 349 | "node": ">=0.10.0" 350 | } 351 | }, 352 | "node_modules/streamsearch": { 353 | "version": "1.1.0", 354 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", 355 | "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", 356 | "engines": { 357 | "node": ">=10.0.0" 358 | } 359 | }, 360 | "node_modules/styled-jsx": { 361 | "version": "5.1.1", 362 | "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", 363 | "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", 364 | "dependencies": { 365 | "client-only": "0.0.1" 366 | }, 367 | "engines": { 368 | "node": ">= 12.0.0" 369 | }, 370 | "peerDependencies": { 371 | "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" 372 | }, 373 | "peerDependenciesMeta": { 374 | "@babel/core": { 375 | "optional": true 376 | }, 377 | "babel-plugin-macros": { 378 | "optional": true 379 | } 380 | } 381 | }, 382 | "node_modules/tslib": { 383 | "version": "2.5.3", 384 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", 385 | "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" 386 | }, 387 | "node_modules/zod": { 388 | "version": "3.21.4", 389 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", 390 | "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", 391 | "funding": { 392 | "url": "https://github.com/sponsors/colinhacks" 393 | } 394 | } 395 | } 396 | } 397 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "heroku-nextjs", 3 | "version": "2.0.0", 4 | "description": "Deploy Next.js server-side React apps to Heroku", 5 | "scripts": { 6 | "dev": "next", 7 | "build": "next build", 8 | "start": "next start -p $PORT" 9 | }, 10 | "engines": { 11 | "node": "20" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/mars/heroku-nextjs.git" 16 | }, 17 | "keywords": [ 18 | "react", 19 | "ssr", 20 | "server-side-rendering" 21 | ], 22 | "author": "Mars Hall", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/mars/heroku-nextjs/issues" 26 | }, 27 | "homepage": "https://github.com/mars/heroku-nextjs#readme", 28 | "dependencies": { 29 | "next": "^13.4.4", 30 | "react": "^18.2.0", 31 | "react-dom": "^18.2.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Head from 'next/head' 3 | import Logo from '../components/logo' 4 | 5 | export default () => ( 6 |
Deploy Next.js universal web apps on Heroku.
30 | 31 |This demo deployment on Heroku is from the repo mars/heroku-nextjs.
32 | 33 |Download this Next.js app as a Heroku-ready template, or follow Production Deployment to push an existing app to Heroku.
34 |