My JavaScript development stack in 2020 — React/Express mono-repo

I find this development stack very flexible and enjoyable to work with. I've used it for the last few years and recently gave it an upgrade and figured it's time to share it!

It's a mono-repo which contains a Frontend package, a Backend package and a shared package for that sweet Isomorphic Javascript goodness 🍰

See the GitHub repo here, along with it's!


React Frontend

  • Unejected (but customised!) CRA React frontend SPA

Node Backend

  • ES6 enabled
  • Single bundle file output
  • Basic Express config
  • Chrome dev tool debugging enabled


  • Isomorphic Javascript goes here!

All packages

  • Jest configured in all packages
  • Webpack aliases in all packages
  • Single ESlint config across all packages
  • JSConfig configured in all packages for easy VSCode import lookup

😍 Easy VSCode aliases import lookup😍 Easy VSCode aliases import lookup


The app/ launches a SPA on port localhost:3000 which once mounted pings the server on localhost:4000 and returns an array of numbers.

The SPA renders like so:

SPA outputSPA output

Here's the component which renders as the 5 elements above:

// packages\app\src\components\Number.js

import React from "react";
import PropTypes from "prop-types";
import { isNumber } from "MM:shared/scripts/core/number";

function Number({ num }) {
    return (
        <div style={{ background: "lightgrey", margin: 20, padding: 10 }}>
            Number provided: <span style={{ color: "blue" }}>{num}</span>
            <br />
            {isNumber(num) ? (
                <span style={{ color: "green" }}>It is a number!</span>
            ) : (
                <span style={{ color: "red" }}>Uh oh, not a number...</span>

Number.defaultProps = {};

Number.propTypes = {
    // Required
    // ...
    // Optional
    num: PropTypes.number

export default Number;

The first two Number components are rendered using local, hard coded data:

<Number num={123} />
<Number num="foo bar" />

The second 3 Number components are rendered based on the server's response:

// packages/app/src/App.js

    .then(response => {
        return response.json();
    .then(data => {
        this.setState({ data });

// ...

{ => (
    <Number key={num} num={num} />

And here is the Express server's code:

// packages/server/src/scripts/express.js

import express from "express";
import cors from "cors";

import { isNumber } from "MM:shared/scripts/core/number";

const port = 4000;

export function init() {
    const app = express();
    app.get("/", (req, res, next) => {
        const data = [123, 456, 789];

        console.log("Hello world");

        if (isNumber( {
        } else {
            next("Data contained a non-number");

    app.listen(port, () => console.log(`Example app listening at [http://localhost:${port}`](http://localhost:${port}`)));

As you can see, both the server and the app access the shared MM:shared alias to /packages/shared/ package!

Also notice the console.log("hello world"); in the server. This can be viewed in the Chrome dev tools! How? The --inspect argument in the server's webpack config.

To open the servers console open the chrome browser's console and you'll see a little green icon once the server npm run dev script has been started.

Node `--inspect`Node --inspect

Click it and a headless console will open which is connected to servers Node script!

hello world

This makes debugging the server so much nicer.

There's plenty more I could write about this mono repo format, but I'll cut it short here and only add more by request — so get in touch! I've also used this same mono-repo but configured with NextJS and Gatsby apps, so if that interests you let me know and I'll write it up.

Also see the files in the GitHub mono repo here.