0
0
Remixframework~5 mins

Multi-tenant applications in Remix

Choose your learning style9 modes available
Introduction

Multi-tenant applications let many users or groups share the same app while keeping their data separate and secure.

You build a web app that serves different companies but uses one codebase.
You want to save hosting costs by sharing resources across clients.
You need to customize features or data views per user group.
You want to manage user access and data isolation easily.
You plan to scale your app to many customers without duplicating code.
Syntax
Remix
import { json } from '@remix-run/node';

export async function loader({ request, params }) {
  const tenantId = getTenantIdFromRequest(request);
  const data = await fetchDataForTenant(tenantId);
  return json(data);
}

function getTenantIdFromRequest(request) {
  // Example: extract tenant from subdomain or headers
  const url = new URL(request.url);
  return url.hostname.split('.')[0];
}

async function fetchDataForTenant(tenantId) {
  // Placeholder function to fetch tenant-specific data
  return {};
}

Use the loader function to fetch data specific to each tenant.

Extract tenant info from the request, like subdomain or headers, to separate data.

Examples
Extract tenant ID from a custom header to load tenant-specific data.
Remix
import { json } from '@remix-run/node';

export async function loader({ request }) {
  const tenantId = request.headers.get('x-tenant-id');
  const data = await getTenantData(tenantId);
  return json(data);
}

async function getTenantData(tenantId) {
  // Fetch tenant data based on tenantId
  return {};
}
Use the first part of the URL path as the tenant ID.
Remix
import { json } from '@remix-run/node';

export async function loader({ request }) {
  const url = new URL(request.url);
  const tenantId = url.pathname.split('/')[1];
  const data = await getTenantData(tenantId);
  return json(data);
}

async function getTenantData(tenantId) {
  // Fetch tenant data based on tenantId
  return {};
}
Get tenant info from user session to personalize data.
Remix
import { json } from '@remix-run/node';

export async function loader({ request }) {
  const tenantId = getTenantFromSession(request);
  const data = await getTenantData(tenantId);
  return json(data);
}

function getTenantFromSession(request) {
  // Example: read tenant from user session cookie
  return 'tenant123';
}

async function getTenantData(tenantId) {
  // Fetch tenant data based on tenantId
  return {};
}
Sample Program

This Remix loader extracts the tenant ID from the subdomain of the request URL. It then fetches data specific to that tenant from a simple in-memory object. The response includes the tenant ID and a welcome message. This shows how to separate data per tenant in a multi-tenant app.

Remix
import { json } from '@remix-run/node';

export async function loader({ request }) {
  const tenantId = getTenantIdFromRequest(request);
  const data = await fetchDataForTenant(tenantId);
  return json({ tenantId, data });
}

function getTenantIdFromRequest(request) {
  const url = new URL(request.url);
  return url.hostname.split('.')[0];
}

async function fetchDataForTenant(tenantId) {
  const fakeDatabase = {
    tenantA: { message: 'Welcome Tenant A!' },
    tenantB: { message: 'Hello Tenant B!' },
  };
  return fakeDatabase[tenantId] || { message: 'Unknown tenant' };
}
OutputSuccess
Important Notes

Always validate tenant IDs to avoid security issues.

Use environment variables or config to manage tenant-specific settings.

Consider performance impacts when scaling many tenants.

Summary

Multi-tenant apps share one codebase but keep data separate per user group.

Extract tenant info from requests to load correct data.

Remix loaders are great places to handle tenant-specific data fetching.