Integrate React with Node.js Express on same Server/Port

In this tutorial, I will show you step by step to integrate React project with Node.js Express Rest API so that we only need to run both on same Server/Port. You will also know how to configure React SPA Routing to avoid 404 on refresh.

Related Posts:
React + Node.js Express + MySQL: CRUD example
React + Node.js Express + PostgreSQL: CRUD example
React + Node.js Express + MongoDB: CRUD example
React + Node.js Express + MySQL/PostgreSQL: JWT Authentication example
React + Node.js Express + MongoDB: JWT Authentication example

Serverless:
React Firebase CRUD with Realtime Database
React Firestore CRUD App example | Firebase Cloud Firestore

Dockerize:
Docker Compose: Node.js Express and MySQL example
Docker Compose: Node.js Express and MongoDB example
Docker Compose: React, Node.js Express, MySQL example
Docker Compose: React, Node.js Express, MongoDB example


React & Node.js Express Application Overview

Assume that we have 2 separated projects: React & Node.js Express like this-

integrate-react-express-on-same-server-project-structure-separated

For example, if we run them separately:

  • Express Server exports Rest Apis at Url: http://localhost:8080/
  • React Client runs at url: http://localhost:8081/

Using React to call Express Rest API:

integrate-react-express-on-same-server-separated-port

Otherwise, when deploying React production-build with Node.js Express project, we only need to run Node Project for the fullstack (React + Node) system.

In this example, we access http://localhost:8080/.

integrate-react-express-on-same-server-port

Technology Stack

  • Node.js
  • Express
  • React 16
  • React Router
  • React Scripts 3

Setup React Client

You can use your own React Project, or just download the source code on Github, or follow these steps to create a new one.

Open cmd and create a new React Project as following command:

npx create-react-app react-crud

After the process is done. We create additional folders and files like the following tree:


public

src

components

add-tutorial.component.js

tutorial.component.js

tutorials-list.component.js

services

tutorial.service.js

App.css

App.js

index.js

package.json


Because I want to keep this tutorial simple and brief, please continue to develop this App with instruction in the post:
React.js CRUD example to consume Web API

Setup Express Server

You can use your own Node.js Project, or just download the source code on Github, or follow these steps to create a new one.

First, we create a folder:

$ mkdir react-express-mysql
$ cd react-express-mysql

Next, we initialize the Node.js App with a package.json file:

npm init

name: (react-express) 
version: (1.0.0) 
description: integrate React and Node.js Express Rest Apis on same server
entry point: (index.js) server.js
test command: 
git repository: 
keywords: react, nodejs, express, sequelize, rest, api
author: bezkoder
license: (ISC)

Is this ok? (yes) yes

The instruction can be found in one of the posts:
Node.js Rest APIs example with Express, Sequelize & MySQL
Node.js Rest APIs example with Express, Sequelize & PostgreSQL
Node.js Rest APIs example with Express, Sequelize & MongoDb

Let’s continue to the most important part.

Integrate React with Node.js Express

Build React App

Currently React Client and Express server work independently on ports 8081 and 8080.

The first thing we need to do is to build React App for production.

Run command:
npm run build
– or yarn build

PS D:\Projects\ReactProjects\react-crud> npm run build

> [email protected] build D:\Projects\ReactProjects\react-crud
> react-scripts build

Creating an optimized production build...
Browserslist: caniuse-lite is outdated. Please run the following command: `yarn upgrade`
Compiled successfully.

File sizes after gzip:

  52.63 KB  build\static\js\2.8091b331.chunk.js
  22.44 KB  build\static\css\2.47e06e2e.chunk.css
  2.38 KB   build\static\js\main.2cd554a3.chunk.js
  774 B     build\static\js\runtime-main.efee8004.js
  144 B     build\static\css\main.9c6cdb86.chunk.css

The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.

The build folder is ready to be deployed.
You may serve it with a static server:

  yarn global add serve
  serve -s build

Find out more about deployment here:

  bit.ly/CRA-deploy

Now you can see new build folder with content as following:

integrate-react-express-on-same-server-react-build-folder

Integrate React production into Node.js Project

In app folder of Node.js Express Project, let’s create views folder.


app

config

controllers

models

routes

views

index.js

package.json

server.js


Now we need to copy all files from React build folder to app/views folder above.

The final Node.js Project folder structure will be like this:

integrate-react-express-on-same-server-final-project

Serve React App from Express

We’re gonna serve static files such as HTML files, CSS files and JavaScript files in app/views folder using the express.static() built-in middleware function.

const express = require("express");

const path = __dirname + '/app/views/';
const app = express();

app.use(express.static(path));

Now, we can load the files in the static directory:

http://localhost:8080/index.html
http://localhost:8080/static/css/2.47e06e2e.chunk.css
http://localhost:8080/static/js/2.8091b331.chunk.js

The final step is to deliver index.html file using res.sendFile(). We will need to pass in a path to the file.

// const path = __dirname + '/app/views/';

app.get('/', function (req,res) {
  res.sendFile(path + "index.html");
});

Now content in server.js file is like this-

const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");

const path = __dirname + '/app/views/';

const app = express();

app.use(express.static(path));

var corsOptions = {
  origin: "http://localhost:8081"
};

app.use(cors(corsOptions));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

const db = require("./app/models");

db.sequelize.sync();

app.get('/', function (req,res) {
  res.sendFile(path + "index.html");
});

require("./app/routes/turorial.routes")(app);

// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}.`);
});

Run Express and React on same Port

Run the Node.js Express server (including React client) with commands:
node server.js

Open browser with url: http://localhost:8080/.
Now you can see the result:

integrate-react-express-on-same-port

React Router 404 Not found on Refresh

Oh yeah! Everything looks good.
But wait, let’s try to refresh the page.
What happened?

integrate-react-express-on-same-server-404-on-refresh

To handle this error, we’re gonna enable hash(#) in React App Routing by using HashRouter.
It will keep the UI route in hash part of the URL, which should not make the server return 404.

So, in React Project, let’s open index.js file and change BrowserRouter into HashRouter.

import React from "react";
import ReactDOM from "react-dom";
import { HashRouter } from "react-router-dom";

import App from "./App";
import * as serviceWorker from "./serviceWorker";

ReactDOM.render(
  <HashRouter>
    <App />
  </HashRouter>,
  document.getElementById("root")
);

serviceWorker.unregister();

Don’t forget to rebuild the React App and copy all files and folders in build directory (React project) into views (Node.js Express project).

Now Our Url is hashed(#) after port number: http://localhost:8080/#/tutorials

integrate-react-express-on-same-server-port

Now you can refresh the page without worrying about 404.

Conclusion

Today we’ve learned how to integrate React with Node.js Express on same Server/Port. We also handle the case React Router 404 Not found on Refresh by adding hash(#) to the urls.

There are many React + Express examples that you can apply this approach to integrate:
React + Node.js Express + MySQL: CRUD example
React + Node.js Express + PostgreSQL: CRUD example
React + Node.js Express + MongoDB: CRUD example
React + Node.js Express + MySQL/PostgreSQL: JWT Authentication example
React + Node.js Express + MongoDB: JWT Authentication example

Further Reading

Dockerize:
Docker Compose: Node.js Express and MySQL example
Docker Compose: Node.js Express and MongoDB example
Docker Compose: React, Node.js Express, MySQL example
Docker Compose: React, Node.js Express, MongoDB example

Source Code

You can find the complete source code for this tutorial at Github.

11 thoughts to “Integrate React with Node.js Express on same Server/Port”

  1. Hello there,
    I did react table-7 for frontend, and node-express-mongodb for backend. I integrated them successfully. May I deploy this site to netlify?

  2. I am using mongoldb online database, following – React + Node.js Express + MongoDB: CRUD example – for front end and back end. But I got this error after integration. How can I fix it?
    db.sequelize.sync();
    TypeError: Cannot read property ‘sync’ of undefined
    at Object. (/Users/JinTang/Desktop/FFUN/2nodejs/server.js:22:14)
    at Module._compile (internal/modules/cjs/loader.js:1133:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)
    at Module.load (internal/modules/cjs/loader.js:977:32)
    at Function.Module._load (internal/modules/cjs/loader.js:877:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:74:12)
    at internal/main/run_main_module.js:18:47

    1. Hi, I don’t know where you found db.sequelize.sync();. We don’t use Sequelize for Mongodb.

        1. Hi, the tutorial illustrates how to integrate certain React Client with Node Express Server. And I use Node + Express + Sequelize for a case.
          The user who comments above uses Node + MongoDB that shouldn’t relate to ORM like Sequelize.

  3. I got ‘TypeError: Cannot read property ‘sync’ of undefined’ for integration. If I delete the db.sequelize.sync(), then server runs but database is not sync. How to fix this issue?

  4. Hello. I have created Node/React webapp with mysql db which is based on your other tutorial. Front- and backend are integrated to same port and it works on my computer just fine. Now i need to host it on local network at workplace. Others can access the frontend on their browsers but REST API calls dont work. Can you do tutorial showing how to use something like NGINX webserver to make it work?

  5. Hey, I was going through all your tutorials and its really good stuff. Love the way its so detailed and well thoguht off

  6. Great tutorial, thanks for writing about it.

    I actually had issues with the HashRouter in react-router-dom v5 so my solution was to place the express routes above the sendFile index.html call and make the sendFile app.get function a /* wildcard, which makes the refresh work as expected.

    require(“./app/routes/turorial.routes”)(app);

    app.get(‘/*’, function (req,res) {
    res.sendFile(path + “index.html”);
    });

    The only downside with this approach is you cannot have the same route defined in express as in your react app, but you can always place a prefix like “/api” to all your express routes to not have this issue.

Comments are closed to reduce spam. If you have any question, please send me an email.