Using Tailwind presets for multiple tenants in Next.js

by Chris Low on Feb 26 2022

When I was tasked to build a multi-tenant SaaS application using Next.js + Tailwind on a monorepo, the internet disappointed me. There was nothing solid out there on how to load a specific Tailwind preset for a specific tenant. This was the solution I came up with, hope this helps ;)

Full repository available here.

Final result for default, Reddit and Discord themed tenants using the exact same codebase with different environment variables!

Final result

Let's dive into it!

We will be starting with the official Next.js with Tailwind example repo. To clone the example, run the following command:

yarn create next-app --example with-tailwindcss with-tailwindcss-app

Setup environment

Create a .env file and define a NEXT_PUBLIC_TENANT environment variable.

NEXT_PUBLIC_TENANT=reddit

Setup Tailwind Presets

Add a tailwind folder to the root of your project with the following structure.

.
└── tailwind
    ├── default
    │   └── preset.js
    ├── reddit
    │   └── preset.js
    └── discord
        └── preset.js

Presets take the exact same shape as the configuration in a tailwind.config.js file. Since presets are merged on top of the default, we only need to include the theme object.

// default preset.js
module.exports = {
  theme: {
    extend: {
      colors: {
        primary: "#2563EB",
      },
    },
  },
};

Add a getPreset() helper function in the tailwind.config.js file

// tailwind.config.js
const getPreset = () => {
  if (!process.env.NEXT_PUBLIC_TENANT)
    return [require(`./tailwind/default/preset.js`)];

  try {
    return [require(`./tailwind/${process.env.NEXT_PUBLIC_TENANT}/preset.js`)];
  } catch (err) {
    return [require(`./tailwind/default/preset.js`)];
  }
};

module.exports = {
  presets: getPreset(),
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

You're almost there

Find and replace all text-blue-600 from index.tsx with text-primary

Yay

That's it! Restart the server when you change the value of NEXT_PUBLIC_TENANT to see the changes.

Note: The values of NEXT_PUBLIC_TENANT correspond to the folder names in ./tailwind

Subscribe to the newsletter

I post about tech, travel and unique personal experiences.