{"id":13527542,"url":"https://github.com/micheleriva/krabs","last_synced_at":"2025-09-30T03:31:32.353Z","repository":{"id":44938696,"uuid":"326439775","full_name":"micheleriva/krabs","owner":"micheleriva","description":"🦀   Express.js/Fastify middleware and virtual host for multi-tenant Next.js applications","archived":true,"fork":false,"pushed_at":"2023-09-25T06:42:33.000Z","size":2551,"stargazers_count":368,"open_issues_count":12,"forks_count":28,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-09-09T10:38:16.676Z","etag":null,"topics":["express-js","express-middleware","expressjs","hacktoberfest","hacktoberfest2021","javascript","krabs","multi-tenant","multitenancy","nextjs","nodejs","tenant-management","tenants","typescript"],"latest_commit_sha":null,"homepage":"https://krabs.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/micheleriva.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["MicheleRiva"],"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2021-01-03T15:35:35.000Z","updated_at":"2025-09-06T02:33:55.000Z","dependencies_parsed_at":"2024-06-18T21:35:42.495Z","dependency_job_id":"1f580ec6-a22d-49f9-9414-c161047eae62","html_url":"https://github.com/micheleriva/krabs","commit_stats":{"total_commits":112,"total_committers":4,"mean_commits":28.0,"dds":0.1785714285714286,"last_synced_commit":"f0296a5421e6a1a32a0fbd4b9dcf7c10b7e5f1b8"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/micheleriva/krabs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micheleriva%2Fkrabs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micheleriva%2Fkrabs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micheleriva%2Fkrabs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micheleriva%2Fkrabs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/micheleriva","download_url":"https://codeload.github.com/micheleriva/krabs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micheleriva%2Fkrabs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":277626821,"owners_count":25849786,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-30T02:00:09.208Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["express-js","express-middleware","expressjs","hacktoberfest","hacktoberfest2021","javascript","krabs","multi-tenant","multitenancy","nextjs","nodejs","tenant-management","tenants","typescript"],"created_at":"2024-08-01T06:01:50.712Z","updated_at":"2025-09-30T03:31:31.882Z","avatar_url":"https://github.com/micheleriva.png","language":"TypeScript","readme":"\u003cimg src=\"/misc/krabs-cover.png\" /\u003e\n\n[![Build Status](https://github.com/micheleriva/krabs/actions/workflows/coverage.yml/badge.svg)](https://github.com/micheleriva/krabs/actions/workflows/coverage.yml)\n[![e2e tests](https://github.com/micheleriva/krabs/actions/workflows/e2e.yml/badge.svg)](https://github.com/micheleriva/krabs/actions/workflows/e2e.yml)\n[![codecov](https://codecov.io/gh/micheleriva/krabs/branch/main/graph/badge.svg?token=s46QYu6uUJ)](https://codecov.io/gh/micheleriva/krabs)\n[![NPM Downloads](https://img.shields.io/npm/dt/krabs)](https://www.npmjs.com/package/krabs)\n[![npm](https://img.shields.io/npm/v/krabs?color=blue\u0026logo=npm)](https://www.npmjs.com/package/krabs)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n\n**Krabs** is an enterprise-ready Express.js/Fastify middleware for serving **thousands** of different websites from a single Next.js instance.\n\n- [Sponsors](#sponsors)\n- [Installation](#installation)\n- [Things to know](#things-to-know)\n- [Installation](#installation)\n- [Getting started](#getting-started)\n  - [Examples](#examples)\n- [Documentation](#documentation)\n- [License](#license)\n\n# Sponsors\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://graphcms.com?utm_source=https://github.com/micheleriva/krabs\"\u003e\n    \u003cimg src=\"/misc/sponsors/sponsor-graphcms.svg\" alt=\"GraphCMS\" target=\"_blank\" width=\"250px\" /\u003e\n  \u003c/a\u003e\n\n  \u003cbr /\u003e\n  \u003ca align=\"center\" href=\"https://github.com/sponsors/micheleriva\" target=\"_blank\"\u003e\n    \u003cb\u003eBecome a sponsor\u003c/b\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n# Installation\n\nKrabs is available on **npm** and can be installed as follows:\n\n**For Express.js** (see on [npm](https://www.npmjs.com/package/krabs))\n\n```bash\nyarn add krabs\n\n# or\n\nnpm install --save krabs\n```\n\n**For Fastify** (see on [npm](https://www.npmjs.com/package/fastify-krabs))\n\n```bash\nyarn add fastify-krabs\n\n# or\n\nnpm insall --save fastify-krabs\n```\n\n# Things to know\n\n- Krabs forces you to use a custom server. Therefore, deployments to Vercel are not supported.\n- `_app` and `_document` pages are common to every website.\n\n# Getting Started\n\nYou can watch a video introduction on **YouTube**:\n\n\u003ca href=\"https://www.youtube.com/watch?v=71NRAnT4G4Q\" target=\"_blank\"\u003e\n  \u003cimg src=\"/misc/krabs-yt-intro.png\" /\u003e\n\u003c/a\u003e\n\n## Examples\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eExpress.js example\u003c/b\u003e\u003c/summary\u003e\n\nLet'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.\nWrite the following configuration inside a `.krabs.js` or `.krabs.config.js` file inside of the root of your project:\n\n```js\nmodule.exports = {\n  tenants: [\n    {\n      name: 'website-1',\n      domains: [\n        {\n          development: /dev\\.[a-z]*\\.local\\.website-1\\.com/, // Regex supported!\n          staging: 'stage.website-1.com',\n          production: 'website-1.com',\n        },\n      ],\n    },\n    {\n      name: 'website-2',\n      domains: [\n        {\n          development: 'local.website-2.com',\n          staging: 'stage.website-2.com',\n          production: /[\\w|\\d|-|_]+\\.website-2.com/, // Regex supported!\n        },\n      ],\n    },\n  ],\n};\n```\n\nCreate an `index.js` file and fill it with the following content:\n\n```js\nconst express = require('express');\nconst next = require('next');\nconst krabs = require('krabs').default;\nconst dev = process.env.NODE_ENV !== 'production';\nconst app = next({ dev });\n\nasync function main() {\n  try {\n    await app.prepare();\n\n    const handle = app.getRequestHandler();\n    const server = express();\n\n    server\n      .get('*', (req, res) =\u003e krabs(req, res, handle, app))\n      .listen(3000, () =\u003e console.log('server ready'));\n  } catch (err) {\n    console.log(err.stack);\n  }\n}\n\nmain();\n```\n\nInside our `.krabs.js` file, we configured two tenants with two different `name` properties: `website-1` and `website-2`.\nSo now let's create two new folders inside of the Next.js' default `pages/` directory:\n\n```txt\npages/\n  - _app.js\n  - website-1\n  - website-2\n```\n\nFeel 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.\nLet's add the following content to `pages/website-1/about.js`:\n\n```jsx\nfunction About() {\n  return \u003cdiv\u003e About website 1 \u003c/div\u003e;\n}\n\nexport default About;\n```\n\nand the following code to `pages/website-2/about.js`:\n\n```jsx\nfunction About() {\n  return \u003cdiv\u003e This is website 2 \u003c/div\u003e;\n}\n\nexport default About;\n```\n\nMap `local.website-1.com` and `local.website-2.com` in your hosts file, then boot the server by typing:\n\n```bash\nnode index.js\n```\n\ngoing 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!\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eFastify example\u003c/b\u003e\u003c/summary\u003e\n\nLet'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.\nWrite the following configuration inside a `.krabs.js` or `.krabs.config.js` file inside of the root of your project:\n\n```js\nmodule.exports = {\n  tenants: [\n    {\n      name: 'website-1',\n      domains: [\n        {\n          development: /dev\\.[a-z]*\\.local\\.website-1\\.com/, // Regex supported!\n          staging: 'stage.website-1.com',\n          production: 'website-1.com',\n        },\n      ],\n    },\n    {\n      name: 'website-2',\n      domains: [\n        {\n          development: 'local.website-2.com',\n          staging: 'stage.website-2.com',\n          production: /[\\w|\\d|-|_]+\\.website-2.com/, // Regex supported!\n        },\n      ],\n    },\n  ],\n};\n```\n\nCreate an `index.js` file and fill it with the following content:\n\n```js\nconst fastify = require('fastify')({ trustProxy: true });\nconst next = require('next');\nconst krabs = require('../dist/fastify-krabs').default;\n\nconst dev = process.env.NODE_ENV !== 'production';\nconst app = next({ dev });\n\nasync function main() {\n  try {\n    await app.prepare();\n    const handle = app.getRequestHandler();\n\n    fastify\n      .get('*', (request, reply) =\u003e krabs(request, reply, handle, app))\n      .listen(3000, () =\u003e console.log('server ready'));\n  } catch (err) {\n    console.log(err.stack);\n  }\n}\n\nmain();\n```\n\nInside our `.krabs.js` file, we configured two tenants with two different `name` properties: `website-1` and `website-2`.\nSo now let's create two new folders inside of the Next.js' default `pages/` directory:\n\n```txt\npages/\n  - _app.js\n  - website-1\n  - website-2\n```\n\nFeel 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.\nLet's add the following content to `pages/website-1/about.js`:\n\n```jsx\nfunction About() {\n  return \u003cdiv\u003e About website 1 \u003c/div\u003e;\n}\n\nexport default About;\n```\n\nand the following code to `pages/website-2/about.js`:\n\n```jsx\nfunction About() {\n  return \u003cdiv\u003e This is website 2 \u003c/div\u003e;\n}\n\nexport default About;\n```\n\nMap `local.website-1.com` and `local.website-2.com` in your hosts file, then boot the server by typing:\n\n```bash\nnode index.js\n```\n\ngoing 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!\n\n\u003c/details\u003e\n\n# Documentation\n\nYou can find the full documentation (with real code examples) [here](https://micheleriva.github.io/krabs/)!\n\n# License\n\nKrabs is _free as in freedom_ and licensed under the [**MIT** license](/LICENSE.md).\n\n\u003cbr /\u003e\n\n\u003cimg src=\"/misc/krabs-bottom.png\" /\u003e\n","funding_links":["https://github.com/sponsors/MicheleRiva","https://github.com/sponsors/micheleriva"],"categories":["Nextjs Projects","TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicheleriva%2Fkrabs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicheleriva%2Fkrabs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicheleriva%2Fkrabs/lists"}