@davaux/multisite
v0.8.1
Published
Multi-site hosting for Davaux — run multiple sites from a single codebase
Readme
@davaux/multisite
Multi-site hosting for Davaux — run multiple sites from a single process, dispatched by Host header.
Installation
npm install @davaux/multisiteBasic setup
// server.ts
import { startMultisite } from '@davaux/multisite'
startMultisite({
sites: [
{
name: 'main',
hostname: 'example.com',
routesDir: './src/routes/main',
},
{
name: 'blog',
hostname: 'blog.example.com',
routesDir: './src/routes/blog',
},
],
}, { port: 3000, cwd: import.meta.dirname })startMultisite auto-detects NODE_ENV — dev mode with file watching and live reload when NODE_ENV !== 'production', production dispatch otherwise. Pass cwd: import.meta.dirname from your server.ts for reliable path resolution.
Shared base + per-site overlay
Use baseDir for routes shared across all sites. Each site's routesDir overlays on top — when both define the same URL pattern and type, the site-specific route wins:
startMultisite({
baseDir: './src/routes/base',
islandsDir: './src/islands/base',
publicDir: './public',
sites: [
{ name: 'tenant-a', hostname: 'a.example.com', routesDir: './src/routes/tenant-a' },
{ name: 'tenant-b', hostname: 'b.example.com', routesDir: './src/routes/tenant-b' },
{ name: 'fallback', hostname: '*' },
],
}, { cwd: import.meta.dirname })'*' as hostname is a catch-all for any host not explicitly registered.
Per-site config
Attach arbitrary data to each site via SiteDefinition.config. Access it in any handler, layout, or middleware via getSite<T>(ctx):
import { getSite } from '@davaux/multisite'
// In server.ts:
startMultisite({
sites: [
{ name: 'acme', hostname: 'acme.example.com', config: { theme: 'blue', name: 'Acme' } },
{ name: 'globex', hostname: 'globex.example.com', config: { theme: 'red', name: 'Globex' } },
],
})
// In any route file:
export default definePage((ctx) => {
const site = getSite<{ theme: string; name: string }>(ctx)
return <h1>Welcome to {site?.name}</h1>
})getSite returns undefined when called outside a multisite server (e.g. in tests).
SiteDefinition options
| Option | Type | Description |
|---|---|---|
| name | string | Unique site identifier used in logging and asset paths |
| hostname | string \| string[] | Host header value(s) that route to this site. '*' is a catch-all |
| routesDir | string? | Site-specific routes directory, overlaid on baseDir |
| islandsDir | string? | Site-specific islands directory, merged with shared islandsDir |
| publicDir | string? | Site-specific static files directory (takes priority over shared publicDir) |
| clientEntry | string? | Site-specific client bundle entry. Overrides shared clientEntry |
| config | T? | Arbitrary per-site data, accessible via getSite<T>(ctx) |
MultisiteConfig options
| Option | Type | Description |
|---|---|---|
| sites | SiteDefinition[] | Site definitions (required) |
| baseDir | string? | Shared base routes directory |
| islandsDir | string? | Shared islands directory — included in every site's client bundle |
| publicDir | string? | Shared static files directory |
| clientEntry | string? | Shared client bundle entry compiled to /_davaux/client.js |
Production build
// build.ts
import { buildMultisite } from '@davaux/multisite/build'
await buildMultisite({
sites: [
{ name: 'main', hostname: 'example.com', routesDir: './src/routes/main' },
],
}, { cwd: import.meta.dirname })Compiles all route files, per-site island bundles, and server.ts / multisite.config.ts to dist/. Run with node dist/server.js.
Advanced: embedding in a custom server
import { buildMultisiteApps, dispatchToSite } from '@davaux/multisite'
import { createServer } from 'node:http'
const apps = await buildMultisiteApps(config, { cwd: import.meta.dirname })
const server = createServer(async (req, res) => {
const handled = await dispatchToSite(apps, req, res)
if (!handled) { res.writeHead(404); res.end('No site') }
})TypeScript
Use defineSites<T> to get type inference on SiteDefinition.config without a type annotation at every call site:
import { defineSites } from '@davaux/multisite'
interface SiteConfig { theme: string }
export const sites = defineSites<SiteConfig>({
sites: [
{ name: 'acme', hostname: 'acme.example.com', config: { theme: 'blue' } },
],
})