DEV Community

Nadim Chowdhury
Nadim Chowdhury

Posted on

How to Build a Multi-Tenant SaaS Application with the MERN Stack

Multi-Tenant SaaS (Software as a Service) applications allow multiple users (tenants) to share the same infrastructure while maintaining isolated data and configurations. In this guide, we will explore how to build a multi-tenant SaaS application using the MERN (MongoDB, Express, React, Node.js) stack.


1. Understanding Multi-Tenancy

Types of Multi-Tenancy:

  • Single Database, Shared Schema: All tenants share the same database and collections, with tenant-specific data identified by a tenantId.
  • Single Database, Separate Schemas: A single database is used, but each tenant has its own schema or set of collections.
  • Separate Databases for Each Tenant: Each tenant gets its own database, providing maximum isolation but higher resource costs.

For this guide, we will use the Single Database, Shared Schema approach for scalability and cost efficiency.


2. Setting Up the MERN Stack

Install Dependencies

npm install express mongoose jsonwebtoken bcryptjs cors dotenv
Enter fullscreen mode Exit fullscreen mode

3. Implementing Tenant Identification

Each request must identify the tenant and ensure data is scoped correctly.

Middleware to Identify Tenant

Create a middleware to extract the tenant ID from the request:

const tenantMiddleware = (req, res, next) => {
  const tenantId = req.headers['x-tenant-id'];
  if (!tenantId) {
    return res.status(400).json({ error: 'Tenant ID is required' });
  }
  req.tenantId = tenantId;
  next();
};

export default tenantMiddleware;
Enter fullscreen mode Exit fullscreen mode

4. Designing the Database Schema

Using a shared schema, we will add a tenantId field to each document.

User Model (MongoDB + Mongoose)

import mongoose from 'mongoose';

const userSchema = new mongoose.Schema({
  tenantId: { type: String, required: true },
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true }
});

const User = mongoose.model('User', userSchema);
export default User;
Enter fullscreen mode Exit fullscreen mode

5. Multi-Tenant Authentication

Register Users for Specific Tenants

import express from 'express';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import User from '../models/User.js';
import tenantMiddleware from '../middleware/tenantMiddleware.js';

const router = express.Router();

router.post('/register', tenantMiddleware, async (req, res) => {
  try {
    const { name, email, password } = req.body;
    const hashedPassword = await bcrypt.hash(password, 10);

    const user = new User({
      tenantId: req.tenantId,
      name,
      email,
      password: hashedPassword
    });

    await user.save();
    res.status(201).json({ message: 'User registered successfully' });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

export default router;
Enter fullscreen mode Exit fullscreen mode

Login and Generate JWT Token

router.post('/login', tenantMiddleware, async (req, res) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ email, tenantId: req.tenantId });
    if (!user) return res.status(400).json({ error: 'Invalid credentials' });

    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) return res.status(400).json({ error: 'Invalid credentials' });

    const token = jwt.sign({ userId: user._id, tenantId: user.tenantId }, 'secret', { expiresIn: '1h' });
    res.json({ token });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});
Enter fullscreen mode Exit fullscreen mode

6. Building the Frontend with React

Handle Tenant-Based API Requests

Ensure that each request includes the tenant ID:

const apiClient = axios.create({
  baseURL: 'http://localhost:5000',
  headers: {
    'x-tenant-id': 'your-tenant-id',
    'Authorization': `Bearer ${localStorage.getItem('token')}`
  }
});
Enter fullscreen mode Exit fullscreen mode

Tenant-Specific Dashboards

Each tenant should see only their relevant data. Use React Context or Redux for state management.


7. Deployment Considerations

Hosting the Backend

  • Use Render, DigitalOcean, or AWS for deploying the Express backend.
  • Use MongoDB Atlas for cloud-based database storage.

Hosting the Frontend

  • Deploy the React app on Vercel or Netlify.

Security Best Practices

  • Use JWT authentication to protect API endpoints.
  • Validate tenantId in every request.
  • Encrypt sensitive user data.

Conclusion

Building a multi-tenant SaaS application using the MERN stack requires careful planning around tenant identification, authentication, and data isolation. By following the steps in this guide, you can create a scalable and secure SaaS application that serves multiple clients efficiently.

Start building your multi-tenant MERN SaaS today! ๐Ÿš€

Support My Work โค๏ธ

If you enjoy my content and find it valuable, consider supporting me by buying me a coffee. Your support helps me continue creating and sharing useful resources. Thank you!

Connect with Me ๐ŸŒ

Letโ€™s stay connected! You can follow me or reach out on these platforms:

๐Ÿ”น YouTube โ€“ Tutorials, insights & tech content

๐Ÿ”น LinkedIn โ€“ Professional updates & networking

๐Ÿ”น GitHub โ€“ My open-source projects & contributions

๐Ÿ”น Instagram โ€“ Behind-the-scenes & personal updates

๐Ÿ”น X (formerly Twitter) โ€“ Quick thoughts & tech discussions

Iโ€™d love to hear from youโ€”whether itโ€™s feedback, collaboration ideas, or just a friendly hello!

Disclaimer

This content has been generated with the assistance of AI. While I strive for accuracy and quality, please verify critical information independently.

Top comments (0)