Now that Heroku has shared plans of removing its free tiers, where else can developers like us host hobby projects?
I was researching on good alternatives to Heroku and came across render.com, railway.app as the 2 best possibilities. Of course there are many others like Fly.io and more.
Since I planned to host an app that needed WebSockets support I couldn't use Railway. Other options like Vercel also did not support WebSockets.
I hosted my MongoDB backend on MongoDB Atlas using its free Shared Plans option with only 512mb of space. It's quite limited but I only wanted to host it as an App Demo so it's fine for me.
Prereqs:
- Github Account
- Render Account
- MongoDB Account
- A Fully Functional MERN Application
Here's the my file structure:
- If you happen to have the same file structure, the scripts would work for you
- If your file structure is slightly different, feel free to edit the package.json scripts mentioned in this article.
(root)/
├── client/
│ ├── src
│ ├── public
│ ├── node_modules
│ ├── .env
│ ├── .gitignore
│ ├── package-lock.json
│ └── package.json
├── server/
│ ├── models
│ ├── index.ts
├── node_modules
├── .env
├── .gitignore
├── package-lock.json
└── package.json
Setting up MongoDB Atlas
A guide on how to set up MongoDB Atlas. Get your query string, something like this MONGO_URI='mongodb+srv:...mongodb.net/mern-app?retryWrites=true&w=majority'
You will also need to add whitelist IP addresses from Render.com later as well, but for now you can add your current IP address to test locally.
Preparing our code
Since we're using WebSockets I want my frontend routes to show on my backend routes. So to serve static pages in production, add this into the server/index.js
// Create a proxy for the CRA dev server
if (process.env.NODE_ENV === 'production') {
//*Set static folder up in production
app.use(express.static('../client/build'));
app.get('*', (req,res) => res.sendFile(path.resolve(__dirname, '../client', 'build','index.html')));
}else if(process.env.NODE_ENV === 'development'){
const feProxy = proxy("http://localhost:3000", {
proxyReqPathResolver: (req) => url.parse(req.originalUrl).path || ""
});
app.use("/*", feProxy);
}
In your package.json in root, add the following scripts:
We will later use render-postbuild as our build command and npm run server as our start command.
"scripts": {
"start": "cd server && ts-node-dev index.ts",
"server": "cd server && ts-node-dev index.ts",
"client": "npm start --prefix client",
"clientinstall": "npm install --prefix client",
"dev": "concurrently \"npm run server\" \"npm run client\"",
"build": "npm install && npm install --prefix client && npm run build --prefix client",
"render-postbuild": "npm install && NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client"
},
Another thing to take note is that your app should run without everything under devDependencies as these dependencies would not be installed in production, which could lead to errors when deploying the app.
For me, my server needed all devDependencies even on production so I moved current devDependencies to dependencies instead. My client did not need tailwind, postcss and autoprefixer in production so those could be left in devDependencies.
"devDependencies": {
"autoprefixer": "^10.4.12",
"postcss": "^8.4.17",
"tailwindcss": "^3.1.8"
}
Once you're done with all the changes, initialise a repository on Github, commit and push changes to your Github Repository.
Deploying on Render
Creating Project on Render
Login to Render.com and head over to your dashboard.
Create a New Web Service with Render
Connect your Github Account
- After connecting your account you can select the repository with your project that you'd like to deploy
- Then click Connect
Setting Configurations
Remember I mentioned we would need to enter more IP addresses to MongoDb Atlas?
- Get your Static Outbound IP addresses here and enter them into Atlas
Configuring Start and Build Commands
Configuring Environmental Variables
- NODE_ENV should be = production
- MONGO_URI is the string we got from MongoDB Atlas
- JWT_SECRET is one of the env variables my app needs, which is not necessary for your app, but this is where you add everything in your .env file when you ran the app locally.
Next, Let Render.com deploy your site!
Click on Events > Deploy to see Deployment Logs
Things to check for
- Ensure that Build command is successful
- Ensure that Start command is successful If anything fails, you would have to read your logs to see what failed, a possible reason would be are that the project did not build correctly (ensure that you did npm install for both the server and client)
It may take over 10 minutes for your site to go live so go take a break in the meantime!
That's It! The site is Live! :)
Tada! It's live!
If its live and you're still having issues like a server selection error with mongo, you might want to check your MONGO_URI and ensure that you're using this env variable and not hardcoding it.
Thanks for reading, leave a comment and let me know what you think! Hope that helps with deployment! :)
Top comments (0)