Krabs
🦀 Express.js/Fastify middleware and virtual host for multi-tenant Next.js applications
**Krabs** is an enterprise-ready Express.js/Fastify middleware for serving **thousands** of different websites from a single Next.js instance. The project is written primarily in TypeScript, distributed under the MIT License license, first published in 2021. Key topics include: express-js, express-middleware, expressjs, hacktoberfest, hacktoberfest2021.
Krabs is an enterprise-ready Express.js/Fastify middleware for serving thousands of different websites from a single Next.js instance.
Sponsors
<div align="center"> <a href="https://graphcms.com?utm_source=https://github.com/micheleriva/krabs"> <img src="/misc/sponsors/sponsor-graphcms.svg" alt="GraphCMS" target="_blank" width="250px" /> </a> <br /> <a align="center" href="https://github.com/sponsors/micheleriva" target="_blank"> <b>Become a sponsor</b> </a> </div>Installation
Krabs is available on npm and can be installed as follows:
For Express.js (see on npm)
bashyarn add krabs # or npm install --save krabs
For Fastify (see on npm)
bashyarn add fastify-krabs # or npm insall --save fastify-krabs
Things to know
- Krabs forces you to use a custom server. Therefore, deployments to Vercel are not supported.
_appand_documentpages are common to every website.
Getting Started
You can watch a video introduction on YouTube:
<a href="https://www.youtube.com/watch?v=71NRAnT4G4Q" target="_blank"> <img src="/misc/krabs-yt-intro.png" /> </a>Examples
<details> <summary><b>Express.js example</b></summary>Let's say that we want to support two different websites with just one Next.js instance, and serve them using just one Express.js server.
Write the following configuration inside a .krabs.js or .krabs.config.js file inside of the root of your project:
jsmodule.exports = { tenants: [ { name: 'website-1', domains: [ { development: /dev\.[a-z]*\.local\.website-1\.com/, // Regex supported! staging: 'stage.website-1.com', production: 'website-1.com', }, ], }, { name: 'website-2', domains: [ { development: 'local.website-2.com', staging: 'stage.website-2.com', production: /[\w|\d|-|_]+\.website-2.com/, // Regex supported! }, ], }, ], };
Create an index.js file and fill it with the following content:
jsconst express = require('express'); const next = require('next'); const krabs = require('krabs').default; const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); async function main() { try { await app.prepare(); const handle = app.getRequestHandler(); const server = express(); server .get('*', (req, res) => krabs(req, res, handle, app)) .listen(3000, () => console.log('server ready')); } catch (err) { console.log(err.stack); } } main();
Inside our .krabs.js file, we configured two tenants with two different name properties: website-1 and website-2.
So now let's create two new folders inside of the Next.js' default pages/ directory:
txtpages/ - _app.js - website-1 - website-2
Feel free to add any page you want inside both of these folders, as they will be treated as they were the default Next.js' pages/ folder.
Let's add the following content to pages/website-1/about.js:
jsxfunction About() { return <div> About website 1 </div>; } export default About;
and the following code to pages/website-2/about.js:
jsxfunction About() { return <div> This is website 2 </div>; } export default About;
Map local.website-1.com and local.website-2.com in your hosts file, then boot the server by typing:
bashnode index.js
going to http://dev.pizza.local.website-1.com/about and http://local.website-2.com/about, you will see the components above rendered by the same Next.js instance!
</details> <details> <summary><b>Fastify example</b></summary>Let's say that we want to support two different websites with just one Next.js instance, and serve them using just one Express.js server.
Write the following configuration inside a .krabs.js or .krabs.config.js file inside of the root of your project:
jsmodule.exports = { tenants: [ { name: 'website-1', domains: [ { development: /dev\.[a-z]*\.local\.website-1\.com/, // Regex supported! staging: 'stage.website-1.com', production: 'website-1.com', }, ], }, { name: 'website-2', domains: [ { development: 'local.website-2.com', staging: 'stage.website-2.com', production: /[\w|\d|-|_]+\.website-2.com/, // Regex supported! }, ], }, ], };
Create an index.js file and fill it with the following content:
jsconst fastify = require('fastify')({ trustProxy: true }); const next = require('next'); const krabs = require('../dist/fastify-krabs').default; const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); async function main() { try { await app.prepare(); const handle = app.getRequestHandler(); fastify .get('*', (request, reply) => krabs(request, reply, handle, app)) .listen(3000, () => console.log('server ready')); } catch (err) { console.log(err.stack); } } main();
Inside our .krabs.js file, we configured two tenants with two different name properties: website-1 and website-2.
So now let's create two new folders inside of the Next.js' default pages/ directory:
txtpages/ - _app.js - website-1 - website-2
Feel free to add any page you want inside both of these folders, as they will be treated as they were the default Next.js' pages/ folder.
Let's add the following content to pages/website-1/about.js:
jsxfunction About() { return <div> About website 1 </div>; } export default About;
and the following code to pages/website-2/about.js:
jsxfunction About() { return <div> This is website 2 </div>; } export default About;
Map local.website-1.com and local.website-2.com in your hosts file, then boot the server by typing:
bashnode index.js
going to http://dev.pizza.local.website-1.com/about and http://local.website-2.com/about, you will see the components above rendered by the same Next.js instance!
</details>Documentation
You can find the full documentation (with real code examples) here!
License
Krabs is free as in freedom and licensed under the MIT license.
<br /> <img src="/misc/krabs-bottom.png" />Contributors
Showing top 3 contributors by commit count.
