Back to all courses
With Heroku's free tier gone, where can you host Node.js apps for FREE? Render has quickly become one of the best options for hosting Node.js apps with a FREE tier. Let's see how it works by deploying an API that will be hosted (and sold) through RapidAPI).
I publish weekly videos about Web Development! I am constantly learning the latest and greatest in Web Development.
This guide will teach you where to host Node.js backends for free. Since Heroku eliminated their free tier, if you're a developer who doesn't want to spend money but still wants to build things, this is the guide for you.
Let's take a look at how to deploy Node.js with TypeScript API to Render instead of Heroku, a platform that is functionally similar to Heroku and has a free tier.
This guide is the third edition of a series on constructing a TypeScript API with Rapid API and Xata. You can follow the first two here:
Integrate Express, RapidAPI, and Xata into your TypeScript API Development (Part 1)
Integrate Express, RapidAPI, and Xata into your TypeScript API Development (Part 2)
In this guide, we'll deploy this API not only to Render but also to the RapidAPI Studio so that we can make money selling it.
RapidAPI also has a Visual Studio Code extension called the RapidAPI Client. Using it; you can test the various endpoints, such as GET, POST, PUT, and DELETE, for the job's API that I created in previous guides.
The intriguing part of this extension is that you can use it across various devices because they are linked to RapidAPI projects. This project can be linked to the one you use to market and sell your APIs on RapidAPI, and others can also connect to it.
We will now go through each of those steps. You can check out the link here to return to part one, and most importantly, you can have a link to the GitHub repository via this link.
Let's rewind a bit. I have a basic table for jobs within Xata. Our API is a jobs API, so we have access to the company, title, job link, geography, etc.
I can run our project through the VSCode terminal with the following command:
sh
npm run start:dev
Another quick recap. Inside the index.ts
file, we have /api/jobs
along with get
, post
, put
, and delete
routes, which are your basic CRUD operations.
ts
import {getXataClient, Job} from './xata';import dotenv from 'dotenv';import express, {Express, Request, Response} from 'express';dotenv.conf();const app: Express = express();const port = process.env.PORT || 3000;const xata = getXataClient();type MyResponse<T> =| {err: string;}| {data: T;};app.get('/api/jobs', async (req: Request, res: Response<MyResponse<Job[]>>) => {try {const jobs = await xata.db.job.getAll();return res.status(200).json({data: jobs});} catch (err) {console.error(err);return res.status(500).json({err: 'Something went wrong'});}});app.post('/api/jobs',async (req: Request<{}, {}, Job>, res: Response<MyResponse<Job>>) => {try {const job = req.body;const createdJob = await xata.db.job.create(job);return res.status(201).json({data: createdJob});} catch (err) {console.error(err);return res.status(500).json({err: 'Something went wrong'});}});app.put('/api/jobs/:id',async (req: Request<{id: string}, {}, Job>,res: Response<MyResponse<Job>>) => {try {const id = req.params.id;const job = req.body;const updatedJob = await xata.db.joob.update(id, job);if (!updatedJob) {return res.status(404).json({err: 'Job not found.'});}return res.status(200).json({data: updatedJob});} catch (err) {console.error(err);return res.status(500).json({err: 'Something went wrong'});}});app.delete('/api/jobs/:id',async (req: Request<{id: string}, {}, {}>,res: Response<MyResponse<Job>>) => {try {const id = req.params.id;const deletedRecord = await xata.db.job.delete(id);if (!deletedRecord) {return res.status(404).json({err: 'Job not found.'});}return res.status(200).json({data: deletedRecord});} catch (err) {console.error(err);return res.status(500).json({err: 'Something went wrong'});}});app.listen(port, () => {console.log(`Server running at port ${port}`);});
We can visit http://localhost:3000/API/jobs
to view the returned data.
We want to start the deployment instantly. You can clone this project or make your own. Ensure your GitHub repository is set up so you can access it from within Render. I've already deployed this application in testing.
I will navigate to the Render homepage. Already logged in, I intend to create a new web service. Web services are servers that host Node.js APIs.
I'll now look inside for the project nodejs-api-with-rapidapi-typescript-xata. We can name it jqq-jobs-api-2. The step includes selecting a region; my closest region is the US East. For the root directory, we are operating a node
. In previous guides, I specified that the engines
property in the package.json file must contain node:18
. This is because the Xata SDK is looking for a built-in fetch, which is not available unless you employ a feature flag or a string such as node:18
.
It will then inquire about the build commands. We will compose the command npm run build
, which may be slightly modified. Therefore, the build command will execute npm install
, followed by rimraf
of the build directory, and finally, tsc
, which performs the actual compilation.
The install
command will ensure that all packages, including rimrraf
, are accessible during the build
command. In addition, rimraf
will delete any existing build information to ensure that we receive a set of clean files. Then tsc
will perform the build
operation, compiling TypeScript to JavaScript. After which, the start command will be npm run start
. Therefore, this command will execute the file index.js
from the build directory.
json
{"name": "nodejs-api-with-rapidapi-typescript-xata","version": "1.0.0","description": "","main": "index.js","engines": {"node": "≥18","scripts": {"build": "npm install && rimraf ./build && tsc","start:dev": "npx nodemon","start": "npm run build && node build/index.js"},"keywords": [],"author": "","license": "ISC","devDependencies": {"@types/node": "^18.11.9","nodemon": "^2.0.20","rimraf": "^3.0.2","ts-node": "^10.9.1","typescript": "^4.8.4"}}
These were the only requirements. Now we can proceed to create this web service, and it will require a few seconds to spin up.
In the meantime, I'd like to navigate to RapidAPI Studio. We've already developed an API project in the past called *Jobs Node.js. Inside the requests section, we can see that all our CRUD requests are already stored in this location.
The RapidAPI Client extension for VS Code enables you to define multiple requests and switch between projects. Signing in will allow you to connect to an existing project, which will populate these requests.
So while this is running, I could test these to ensure that I receive all of my data and can execute my GET,POST, PUT, and DELETE requests. All of those things were available for testing, which is extremely convenient.
Now comes the last part. We need to make the API publicly accessible in RapidAPI so we can sell it. So head over to the Hub Listing section.
For the base URL, copy the URL from the link directly beneath the web service on Render. Paste it in the Base URL field on the Hub Lsiting page. Here, you can also upload a logo, choose a category, and provide a brief description, such as "This is an API for developer jobs".
We could add additional information to the readme file and add documentation. The documentation will be derived from the endpoints we add, so it will be relatively straightforward.
Inside the endpoints section, we will create our single endpoint. Get Jobs
is the name we'll give to the get endpoint that retrieves the actual jobs. In the description, we can state, "Get all developer jobs," while the endpoint link can read /api/jobs
. What's interesting is that it will generate code snippets for those who wish to use our API.
The next step is to monetize our API. You can specify the various plans for your API and set usage limits for each one.
Below is how it will appear on the Rapid API Hub, where you will receive code snippets for the endpoint and can test it.
However, we must first test this to see if it functions properly. In addition, we should add our API key to the database URL. Therefore, I will simply copy this API key into my .env.local
file, and then we will add it to the application's environment on Render.
We can add an environment variable using the environment option. I'm going to paste the API key and associated value into the value field. Then, we must save and deploy latest commit, ensure that the deployment was successful, and proceed with testing.
Now, we can test the endpoint directly. Copy the URL and paste it into the browser, and append /api/jobs to the URL like this: jqq-jobs-api-2.onrender.com/api/jobs
. You will notice our API is operational, and it returns the following data:
Now we can also test the endpoint from its page on Rapid API Hub and see if it is returning proper data. Note that we did not add the remaining endpoints for all the CRUD routes. We're only doing the reads that make sense from a public perspective, but the rest of them are not available in RapidAPI Hub. We have protected them so that only the appropriate individuals can update and delete data, etc., but if you want to, you can add them using the same steps.
In summary, we discovered how to run a Node.js project that employs TypeScript, Xata as the database, RapidAPI for developing and testing APIs, and Render's free tier for deployment. This guide is the answer to the question, "What should we do next after Heroku removed its free tier?"