DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Building a Full-Stack Resume Screening Application With AI
  • Building a Tic-Tac-Toe Game Using React
  • Mastering Full-Stack Development: A Comprehensive Beginner’s Guide to the MERN Stack
  • Cross-Platform Mobile Application Development: Evaluating Flutter, React Native, HTML5, Xamarin, and Other Frameworks

Trending

  • The Missing `bandit` for AI Agents: How I Built a Static Analyzer for Prompt Injection
  • From 24 Hours to 2 Hours: How We Fixed a Broken BI System With Apache Airflow
  • How to Interpret the Number of Spring ApplicationContexts in Integration Tests
  • Why AI-Generated Code Breaks Your Testing Assumptions
  1. DZone
  2. Coding
  3. Frameworks
  4. Monorepo Development With React, Node.js, and PostgreSQL With Prisma and ClickHouse

Monorepo Development With React, Node.js, and PostgreSQL With Prisma and ClickHouse

Simplify full-stack development by using a monorepo to house your React frontend, Node.js backend, and PostgreSQL database, all accessed through Prisma.

By 
Syed Siraj Mehmood user avatar
Syed Siraj Mehmood
·
Jun. 05, 25 · Analysis
Likes (6)
Comment
Save
Tweet
Share
4.4K Views

Join the DZone community and get the full member experience.

Join For Free

What's the Big Idea?

Building web apps with separate frontends, backends, and databases can be a headache. A monorepo puts everything in one place, making it easier to share code, develop locally, and test the whole app together. We showed how to build a simple signup dashboard using React, Node.js, PostgreSQL (with Prisma for easy database access), and optionally ClickHouse for fast data analysis, all within a monorepo structure. This setup helps you scale your app cleanly and makes life easier for your team.

In this guide, we're going to build a super simple app that shows how many people sign up each day. We'll use:

  • React: To make the pretty stuff you see on the screen.
  • Node.js with Express: To handle the behind-the-scenes work and talk to the database.
  • PostgreSQL: Our main place to store important info.
  • Prisma: A clever tool that makes talking to PostgreSQL super easy and helps avoid mistakes.
  • ClickHouse (optional): A really fast way to look at lots of data later on.
  • All living together in one monorepo!

Why Put Everything Together?

  • Everything in one spot: Issues, updates, and reviews all happen in the same place.
  • Easy peasy development: One setup for everything! Shared settings and simple ways to start the app.
  • Sharing is caring (Code!): Easily reuse little bits of code across the whole app.
  • Testing the whole thing: You can test how the frontend, backend, and database work together, all at once.
  • Grows with you: Adding new parts to your app later is a breeze.

What We're Making: A Signup Tracker

Imagine a simple page that shows how many people signed up each day using a chart:

  • Frontend (React): The part you see. It'll have a chart (using Chart.js) that gets the signup numbers and shows them.
  • Backend (Express): The brain. It will grab the signup numbers from the database.
  • Database (PostgreSQL): Where we keep the list of who signed up and when. We can also use ClickHouse later to look at this data in cool ways.
  • Prisma: Our friendly helper that talks to PostgreSQL for us.

How It's All Organized

Plain Text
 
visualization-monorepo/
│
├── apps/
│   ├── frontend/        # The React stuff
│   └── backend/         # The Node.js + Express + Prisma stuff
│
├── packages/
│   └── shared/          # Bits of code we use in both the frontend and backend
│
├── db/
│   └── schema.sql       # Instructions for setting up our PostgreSQL database and adding some initial info
│
├── docker-compose.yml   # Tells your computer how to run all the different parts together
├── .env                 # Where we keep secret info, like database passwords
├── package.json         # Keeps track of all the tools our project needs
└── README.md            # A file explaining what this project is all about


Setting Up the Database (PostgreSQL)

Here's the basic structure for our db/schema.sql file:

SQL
 
CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email TEXT NOT NULL,
  date DATE NOT NULL
);

-- Let's add some fake signup data
INSERT INTO users (email, date) VALUES
('[email protected]', '2024-04-01'),
('[email protected]', '2024-04-01'),
('[email protected]', '2024-04-02');


This code creates a table called users with columns for a unique ID, email address, and the date they signed up. We also put in a few example signups.

Getting Prisma Ready (Backend)

This is our apps/backend/prisma/schema.prisma file:

SQL
 
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id    Int    @id @default(autoincrement())
  email String
  date  DateTime
}


This tells Prisma we're using PostgreSQL and where to find it. The User model describes what our users table looks like.

Here's how we can use Prisma to get the signup counts:

JavaScript
 
const signups = await prisma.user.groupBy({
  by: ['date'],
  _count: true,
  orderBy: { date: 'asc' },
});


This code asks Prisma to group the users by the date they signed up and count how many signed up on each day, ordering the results by date.

Building the Backend (Express API)

This is our apps/backend/src/routes/signups.ts file:

TypeScript
 
import express from 'express';
import { PrismaClient } from '@prisma/client';

const router = express.Router();
const prisma = new PrismaClient();

router.get('/api/signups', async (req, res) => {
  const data = await prisma.user.groupBy({
    by: ['date'],
    _count: { id: true },
    orderBy: { date: 'asc' },
  });

  res.json(data.map(d => ({
    date: d.date.toISOString().split('T')[0],
    count: d._count.id,
  })));
});

export default router;


This code sets up a simple web address (/api/signups) that, when you visit it, will use Prisma to get the signup data and send it back in a format the frontend can understand (date and count).

Making the Frontend (React + Chart.js)

This is our apps/frontend/src/App.tsx file:

TypeScript
 
import { useEffect, useState } from 'react';
import { Line } from 'react-chartjs-2';

function App() {
  const [chartData, setChartData] = useState([]);

  useEffect(() => {
    fetch('/api/signups')
      .then(res => res.json())
      .then(setChartData);
  }, []);

  return (
    <Line
      data={{
        labels: chartData.map(d => d.date),
        datasets: [{ label: 'Signups', data: chartData.map(d => d.count) }],
      }}
    />
  );
}

export default App;


This React code fetches the signup data from our backend API when the app starts and then uses Chart.js to display it as a line chart.

Sharing Code (Types)

This is our packages/shared/types.ts file:

TypeScript
 
export interface SignupData {
  date: string;
  count: number;
}


We define a simple structure for our signup data. Now, both the frontend and backend can use this to make sure they're talking about the same thing:

TypeScript
 
import { SignupData } from '@shared/types';


Running Everything Together (Docker Compose)

This is our docker-compose.yml file:

YAML
 
version: '3.8'
services:
  db:
    image: postgres
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - ./db:/docker-entrypoint-initdb.d

  backend:
    build: ./apps/backend
    depends_on: [db]
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/appdb

  frontend:
    build: ./apps/frontend
    ports:
      - "3000:3000"
    depends_on: [backend]


This file tells your computer how to run the PostgreSQL database, the backend, and the frontend all at the same time. depends_on makes sure things start in the right order.

Super Fast Data Crunching (ClickHouse)

If you have tons of data and want to analyze it really quickly, you can use ClickHouse alongside PostgreSQL. You can use tools to automatically copy data from PostgreSQL to ClickHouse.

Why ClickHouse is Cool

  • Blazing fast: It's designed to quickly count and group huge amounts of data.
  • Great for history: Perfect for looking at trends over long periods.
  • Plays well with others: You can use it with PostgreSQL as a separate place to do your analysis.

Here's an example of how you might set up a table in ClickHouse:

SQL
 
CREATE TABLE signups_daily
(
  date Date,
  count UInt32
)
ENGINE = MergeTree()
ORDER BY date;


Making Development Easier

  • Turborepo or Nx: Tools to speed up building and testing different parts of your monorepo.
  • ESLint and Prettier: Keep your code looking consistent with shared rules.
  • Husky + Lint-Staged: Automatically check your code for style issues before you commit it.
  • tsconfig.base.json: Share TypeScript settings across your projects.

Why This Is Awesome in Real Life

  • One download: You only need to download the code once to get everything.
  • One place for everything: Easier to manage updates and who owns different parts of the code.
  • Fewer mistakes: Sharing code types helps catch errors early.
  • Easy to get started: New team members can get up and running quickly.

Wrapping Up

Using a monorepo with React, Node.js, and PostgreSQL (with Prisma) is a smart way to build full-stack apps. It keeps things organized, makes development smoother, and sets you up for growth. Adding ClickHouse later on gives you powerful tools for understanding your data.

Whether you're building a small project or something that will grow big, this approach can make your life a lot easier.

What's Next?

  • Add ways for users to log in securely (using tools like Clerk, Auth0, or Passport.js).
  • Automatically copy data to ClickHouse for faster analysis.
  • Add features like showing data in pages, saving data temporarily (caching with Redis), or letting users filter the data.
  • Put your app online using services like Fly.io, Railway, Render, or Vercel (for the frontend).
ClickHouse Monorepo Node.js React (JavaScript library) PostgreSQL Framework

Opinions expressed by DZone contributors are their own.

Related

  • Building a Full-Stack Resume Screening Application With AI
  • Building a Tic-Tac-Toe Game Using React
  • Mastering Full-Stack Development: A Comprehensive Beginner’s Guide to the MERN Stack
  • Cross-Platform Mobile Application Development: Evaluating Flutter, React Native, HTML5, Xamarin, and Other Frameworks

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook