Skip to content

Plugins

Plugins let you package and reuse groups of routes, middleware, and startup logic. They are the recommended way to organize production apps into modular units.


Plugin vs Middleware

MiddlewarePlugin
Registered withapp.use()app.register()
Can be asyncYes (but app.use() doesn't await)Yes — register() awaits async plugins
Typical useRequest processing (auth, logging, parsing)App setup (DB connections, routes, sub-apps)

Your First Plugin

A plugin is any function with the signature (app, options) => void | Promise<void>:

ts
import mimi from 'mimi.js';
import type { Plugin } from 'mimi.js';

const helloPlugin: Plugin = (app, options) => {
  const prefix = options.prefix as string ?? '';

  app.get(`${prefix}/hello`, (req, res) => {
    res.json({ message: 'Hello from plugin!' });
  });
};

const app = mimi();
await app.register(helloPlugin, { prefix: '/api' });

// GET /api/hello now works
app.listen(3000);

Sync Plugin

Bundle routes and middleware together:

ts
import type { Plugin } from 'mimi.js';
import { json, cors } from 'mimi.js';

const apiPlugin: Plugin = (app) => {
  app.use('/api', json());
  app.use('/api', cors({ origin: process.env.ALLOWED_ORIGIN }));

  app.get('/api/status', (req, res) => {
    res.json({ status: 'ok', uptime: process.uptime() });
  });
};

app.register(apiPlugin);
app.listen(3000);

Async Plugin

Use an async plugin when setup requires awaiting something (database, config service, etc.):

ts
import mimi, { json } from 'mimi.js';
import { mongodbManager } from 'mimi.js';
import type { Plugin } from 'mimi.js';

const databasePlugin: Plugin = async (app, options) => {
  await mongodbManager.connect(options.uri as string);
  console.log('Database connected');

  const User = mongodbManager.createCollection('User', {
    name:  { type: String, required: true },
    email: { type: String, required: true },
  }) as any;

  app.get('/users', async (req, res) => {
    res.json(await User.find());
  });

  app.post('/users', async (req, res) => {
    const user = await User.create(req.body);
    res.status(201).json(user);
  });
};

const app = mimi();
app.use(json());

// register() awaits the plugin before continuing
await app.register(databasePlugin, { uri: process.env.MONGO_URI! });

app.listen(3000);

WARNING

app.register() returns a Promise for async plugins. Always await it before calling app.listen().


Composing Multiple Plugins

ts
// src/main.ts
import mimi, { json, cors, security, requestLogger } from 'mimi.js';
import { authPlugin } from './plugins/auth.plugin';
import { usersPlugin } from './plugins/users.plugin';

const app = mimi();

app.use(json());
app.use(cors());
app.use(security());
app.use(requestLogger);

app.register(authPlugin, { prefix: '/api/v1' });
await app.register(usersPlugin, { dbUri: process.env.MONGO_URI! });

app.setErrorHandler((err, req, res) => {
  const status = (err as any).status ?? 500;
  res.statusCode = status;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify({ error: err.message }));
});

app.listen(Number(process.env.PORT) || 3000);

Health Check Plugin

ts
import type { Plugin } from 'mimi.js';
import os from 'os';

const healthPlugin: Plugin = (app, options) => {
  const version = options.version as string ?? '1.0.0';

  app.get('/health', (req, res) => {
    res.json({
      status: 'ok',
      version,
      uptime: process.uptime(),
      memory: process.memoryUsage().rss,
      host: os.hostname(),
    });
  });
};

app.register(healthPlugin, { version: process.env.npm_package_version });

Plugin Type Reference

ts
type Plugin = (
  app: MimiApp,
  options: Record<string, unknown>,
) => void | Promise<void>;

app.register() signature:

ts
register(plugin: Plugin, options?: Record<string, unknown>): this | Promise<this>

Released under the ISC License.