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!
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
Top comments (0)