Skip to content

Fastify

Integration with Fastify using a plugin.

Basic Setup

typescript
import Fastify from 'fastify';
import { createTenantManager, createFastifyPlugin } from 'drizzle-multitenant';
import config from './tenant.config';

const fastify = Fastify({ logger: true });
const tenants = createTenantManager(config);

// Register tenant plugin
fastify.register(createFastifyPlugin, {
  manager: tenants,
  extractTenantId: (request) => request.headers['x-tenant-id'] as string,
  onTenantResolved: (tenantId, request) => {
    request.log.info({ tenantId }, 'Tenant resolved');
  },
});

Using in Routes

typescript
fastify.get('/users', async (request) => {
  const db = request.tenantDb!;
  return db.select().from(schema.users);
});

fastify.post<{ Body: { email: string; name: string } }>('/users', async (request, reply) => {
  const db = request.tenantDb!;
  const { email, name } = request.body;

  const [user] = await db
    .insert(schema.users)
    .values({ email, name })
    .returning();

  return reply.status(201).send(user);
});

Plugin Options

typescript
fastify.register(createFastifyPlugin, {
  manager: tenants,
  extractTenantId: (request) => request.headers['x-tenant-id'] as string,
  validateTenant: async (id) => checkTenantExists(id),
  onTenantResolved: (tenantId, request) => { /* ... */ },
});
OptionTypeDescription
managerTenantManagerRequired. The tenant manager instance
extractTenantId(request) => stringRequired. Extract tenant ID from request
validateTenant(id) => Promise<boolean>Optional. Validate tenant exists
onTenantResolved(tenantId, request) => voidOptional. Called when tenant is resolved

Request Decorators

The plugin decorates the request with:

PropertyTypeDescription
request.tenantDbDrizzleDbTenant-scoped database instance
request.tenantIdstringCurrent tenant ID

Full Example

See the Fastify example for a complete working project.

Released under the MIT License.