Moving Your Full Stack React App From Heroku to Render
Are you in a coding academy but you are following a tutorial for a capstone project via Heroku and you realize that Heroku is not free anymore?
Or did you finish your capstone project and you need to migrate it to a working server so your project stays alive?
Update (March 6, 2023): it turns out that the free Postgres database is only available for 90 days and then it gets deleted.
Follow these series of steps to deploy your goods to render.com so you don’t have to scroll through the endless unanswered questions on Discord and suffer 2 days of troubleshooting like me!
If you want to migrate your app from Heroku to Render, there is documentation for that here: https://render.com/docs/migrate-from-heroku.
Summary of steps for deployment on Render:
- Create a render.com account
- Deploy your front-end app
- Create and set up a PostgreSQL database
- Deploy your back-end app
- Finishing touches
- Troubleshooting
Step 1: Create a render.com account
Head to render.com and get started for free using your GitHub account. Signing in with your GitHub account will make deploying easy because you can choose a repository in your account to deploy.
Step 2: Deploy your front-end app
Once in the dashboard, click on the purple “New +” button and then on Static Site.
Next, connect the front-end repository from your GitHub.
Fill in the page: create a unique name for your site. If your app isn’t built with yarn, you can change it to “npm run build” under Build Command or the appropriate build command. For Publish directory, enter “build”.
Update (August 8, 2023): Render doesn’t know what the nodemon is so the build will fail. Andrii Lischchyna reached out to me on LinkedIn and told me a fix to this issue after this step: we need to write “npm install” under Build Command. This will install the necessary dependencies from the package.json within the Render environment.
Click on “Create Static Site” and wait for about 5 minutes for the deployment. Later, we will go back to the front-end code to change the fetch URLs once we deploy the back-end app.
Step 3: Create and set up a PostgreSQL database
Back in the dashboard, click on the purple “New +” button and then on PostgreSQL.
Fill in the page: create a name and then leave Database and User blank for something randomly generated (unless you want to specify). Select a Region (i.e. Oregon (US West)). Select a PostgreSQL Version. You may leave the Datadog API Key blank. Select “Free” (unless you want to choose something else). Then click “Create Database”.
After a few minutes, you’ll have a hosted PostgreSQL database. Within the database information page, go under the “Info” tab and scroll down to “Connections”.
Important note: this is where you get the Hostname, Port, Database, Username, and Password. Under PSQL Command, reveal it to show the hostname/address — it starts with the Hostname and then a server location. For example, mine is “[Hostname].oregon-postgres.render.com”. You will need this to connect to the database.
Update (May 1, 2023): please read and re-read the important note above. If you skip this step, you won’t be able to connect the database for the next steps.
Ensure you can access the Postgres database
On the same database information page, under Access Control, click on “+ Add Source” and add your own IP address (which should automatically generate). Click “Save”.
Connect to the Postgres database on your desktop
Open up the pgAdmin4 program on your desktop. Once logged in, right-click on “Servers” under Browser > “Register” > “Server…”.
Under “General”, name the server anything. Then under “Connection”, fill in the information you noted on Render and click “Save”:
- Host name/address: (see instruction above)
- Port: 5432
- Maintenance database: (Render Database name)
- Username: (Render Username)
- Password: (Render Password)
After saving, you should see the Render database in the browser:
Grant privileges
Right-click on the Render database name and then on “Properties”. Go to “Default Privileges” and click on the plus sign. Under the Grantee in Tables, select the Render username, then click on “All” under Privileges, and Grantor should be the Render database name. Click “Save”.
Use the Query Tool to create your tables
Right-click on the Render database then on “Query Tool”. Under “Query”, create the necessary tables you need.
CREATE TABLE users (
ID serial PRIMARY KEY,
name VARCHAR(100),
email text UNIQUE NOT NULL,
entries BIGINT DEFAULT 0,
joined TIMESTAMP NOT NULL
);
CREATE TABLE login (
ID serial PRIMARY KEY,
hash VARCHAR (100) NOT NULL,
email text UNIQUE NOT NULL
);
Now your database is set up! (Updated, May 1, 2023: added these QUERIES for the 2 tables.)
Step 4: Deploy your back end app
Back in the dashboard, click on the purple “New +” button and then on Web Service.
Connect the back-end repository from your GitHub.
Fill in the page: create a unique name. Select “Node” for your Environment. If your app isn’t built with yarn, you can change it to “npm” under Build Command or the appropriate build command. For Start Command, enter “node [file name]” (i.e. “node server.js” for mine).
Click on “Create Web Service” and wait about 5–6 minutes for the deployment. After that, you’ll see the back-end app service page with a live URL. Note this URL down to change the fetch URLs in the front end.
Step 5: Finishing touches
Edit the front-end code with the back-end URL
Edit your front-end code and look for all the previous Heroku URLs. An easy way is to just search for “Heroku” and replace all the links with the Render URL.
Commit and push your changes via Git! Render will automatically re-deploy.
Update (August 8, 2023): Andrii Lishchyna shared his debugging knowledge here about the issue with sending a photo to get the face box from the Clarifai API (using the apiCallHandler function), receiving this error:
Aug 1 06:21:29 PM ReferenceError: fetch is not defined
Aug 1 06:21:29 PM at Object.apiCallHandler (/opt/render/project/src/controllers/image.js:37:3)
Aug 1 06:21:29 PM at /opt/render/project/src/server.js:40:44
Aug 1 06:21:29 PM at Layer.handle [as handle_request] (/opt/render/project/src/node_modules/express/lib/router/layer.js:95:5)
Aug 1 06:21:29 PM at next (/opt/render/project/src/node_modules/express/lib/router/route.js:144:13)
Aug 1 06:21:29 PM at Route.dispatch (/opt/render/project/src/node_modules/express/lib/router/route.js:114:3)
Aug 1 06:21:29 PM at Layer.handle [as handle_request] (/opt/render/project/src/node_modules/express/lib/router/layer.js:95:5)
Aug 1 06:21:29 PM at /opt/render/project/src/node_modules/express/lib/router/index.js:284:15
Aug 1 06:21:29 PM at Function.process_params (/opt/render/project/src/node_modules/express/lib/router/index.js:346:12)
Aug 1 06:21:29 PM at next (/opt/render/project/src/node_modules/express/lib/router/index.js:280:10)
Aug 1 06:21:29 PM at cors (/opt/render/project/src/node_modules/cors/lib/index.js:188:7)
Aug 1 06:25:14 PM ReferenceError: fetch is not defined
Aug 1 06:25:14 PM at Object.apiCallHandler (/opt/render/project/src/controllers/image.js:37:3)
Aug 1 06:25:14 PM at /opt/render/project/src/server.js:40:44
Aug 1 06:25:14 PM at Layer.handle [as handle_request] (/opt/render/project/src/node_modules/express/lib/router/layer.js:95:5)
Aug 1 06:25:14 PM at next (/opt/render/project/src/node_modules/express/lib/router/route.js:144:13)
Aug 1 06:25:14 PM at Route.dispatch (/opt/render/project/src/node_modules/express/lib/router/route.js:114:3)
Aug 1 06:25:14 PM at Layer.handle [as handle_request] (/opt/render/project/src/node_modules/express/lib/router/layer.js:95:5)
Aug 1 06:25:14 PM at /opt/render/project/src/node_modules/express/lib/router/index.js:284:15
Aug 1 06:25:14 PM at Function.process_params (/opt/render/project/src/node_modules/express/lib/router/index.js:346:12)
Aug 1 06:25:14 PM at next (/opt/render/project/src/node_modules/express/lib/router/index.js:280:10)
Aug 1 06:25:14 PM at cors (/opt/render/project/src/node_modules/cors/lib/index.js:188:7)
Andrii says: this article is very helpful for fixing this issue. We must install node-fetch, because node doesn’t have a fetch function in the box.
npm install node-fetch
After that, we must add “type”: “module” in package.json, then replace the required method with to import method.
For example:
const register = require("./controllers/register");
TO:
import registerHandler from "./controllers/register.js";
In register.js:
module.exports = { registerHandler: registerHandler };
TO:
export default registerHandler;
Thank you, Andrii for the knowledge share!
Connect the Postgres database to your back-end app
Go to your back-end code and edit the file that contains the database connection information. Add the hostname/address, port, user, password, and database. You can use environmental variables to store this information which you can add to the back-end app settings:
Commit and push your changes and Render will automatically re-deploy.
Now play with your front-end app and check to make sure that you’re able to register and sign in and that your API still works. You now have officially migrated to Render from Heroku!
Troubleshooting
People have messaged me to help them with their issues. The most common issue is connecting the database to the backend app. Here are some troubleshooting tips to try:
- Ensure that your DATABASE connection is complete with the appropriate information. For example, the DATABASE_URL is the INTERNAL URL found in the Render database. The HOST is the Hostname; The Port is 5432 or whatever the database has; Double check the Username/Password; the Database is the Database name (it is NOT the same as Hostname).
- Ensure that you created your tables in the Postgres database because your registration won’t work if your database is empty.
- Ensure that you deployed your apps.
- Ensure that you referenced your backend app API URL in the frontend app.
I hope this article helped you because I spent a lot of time figuring out how to get through the roadblocks and errors by troubleshooting, Googling, walking around, reading all the Render docs, and reaching out to my developer friends to see if they can help.
Special thanks to Desmond for helping me fight the last error boss monster. Thank you so much!
Feel free to connect and let me know on LinkedIn when you successfully completed all this or if you have any debugging tips!