Skip to content

Instantly share code, notes, and snippets.

Last active August 23, 2023 07:21
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save brentjanderson/dcb59c46023c67c44eb12492b038ff84 to your computer and use it in GitHub Desktop.
Save brentjanderson/dcb59c46023c67c44eb12492b038ff84 to your computer and use it in GitHub Desktop.
Running RedwoodJS on Heroku

Redwood aims to be a serverless framework. But what if you really want to run it on Heroku?

This guide aims to walk you through each piece required to make it work.

Running RedwoodJS On Heroku

  1. Add app.json, Procfile, config/nginx.conf.erb, index.js
  2. yarn workspace api add @redwoodjs/api-server
  3. yarn remove -W @redwoodjs/core && yarn add -W @redwoodjs/core pm2
  4. Update your root package.json with the following scripts:
    "scripts": {
        "build": "rw build",
        "start": "node index.js"
  5. Set apiProxyPath in redwood.toml to apiProxyPath = "/api"

Note that you will need to manually add the heroku/nginx buildpack manually to your app if you are setting this up on an already created Heroku stack.

"scripts": {
"postdeploy": "yarn rw db seed"
"addons": [
"plan": "heroku-postgresql",
"options": {
"version": "12"
"buildpacks": [
"url": "heroku/nodejs"
"url": "heroku/nginx"
var pm2 = require('pm2')
var fs = require('fs')
name: 'my-cool-app-pm2', // Change this to whatever you want
node_args: '-r dotenv/config',
script: './node_modules/@redwoodjs/api-server/dist/index.js',
args: `-f api/dist/functions --socket /tmp/nginx.socket`,
env: {
NODE_ENV: 'production',
function (err) {
if (err)
return console.error(
'Error while launching applications',
err.stack || err
console.log('PM2 and application has been succesfully started')
if (process.env.DYNO) {
console.log(`Signaling to Nginx buildpack that we're ready to go`)
fs.openSync('/tmp/app-initialized', 'w')
// Display logs in standard output
pm2.launchBus(function (err, bus) {
console.log('[PM2] Log streaming started')
bus.on('log:out', function (packet) {
console.log('[App:%s] %s',,
bus.on('log:err', function (packet) {
console.error('[App:%s][Err] %s',,
# This file must be located at config/nginx.conf.erb
# From the NGINX buildpack:
daemon off;
# Heroku dynos have at least 4 cores.
worker_processes <%= ENV['NGINX_WORKERS'] || 4 %>;
events {
use epoll;
accept_mutex on;
worker_connections <%= ENV['NGINX_WORKER_CONNECTIONS'] || 1024 %>;
http {
gzip on;
gzip_comp_level 2;
gzip_min_length 512;
server_tokens off;
log_format l2met 'measure#nginx.service=$request_time request_id=$http_x_request_id';
access_log <%= ENV['NGINX_ACCESS_LOG_PATH'] || 'logs/nginx/access.log' %> l2met;
error_log <%= ENV['NGINX_ERROR_LOG_PATH'] || 'logs/nginx/error.log' %>;
include mime.types;
default_type application/octet-stream;
sendfile on;
# Must read the body in 5 seconds.
client_body_timeout 5;
upstream app_server {
server unix:/tmp/nginx.socket fail_timeout=0;
server {
server_name _;
listen <%= ENV["PORT"] %>;
keepalive_timeout 5;
location / {
root /app/web/dist;
try_files $uri /index.html;
location /api/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server/;
release: yarn rw prisma migrate deploy
web: bin/start-nginx node index.js
Copy link

Glad to hear it! On the NGINX buildpack, did you already have an app that you added this to? App.json buildpacks only apply when building a newly-created app. I'll update the instructions with that. 👍 Thanks!

it was the first deploy in a brand new app. Was quickly fixable, just happy to have my fullstack RedwoodJS running on one heroku dyno :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment