Skip to main content

Express Compatibility

Experimental

The Express compatibility layer is experimental and may change in future versions. Use it primarily for integrating third-party Express libraries. For new code, prefer using Balda's native APIs.

Balda.js provides an Express compatibility layer that allows you to integrate Express-based libraries like AdminJS, Passport, and other Express middleware into your Balda application.

Installation

Install the Express types for TypeScript support:

npm install express
npm install -D @types/express

Quick Start

Mounting an Express Router

Use mountExpressRouter to mount an entire Express router at a specific path:

import { Server } from 'balda-js';
import AdminJS from 'adminjs';
import AdminJSExpress from '@adminjs/express';

const admin = new AdminJS({ resources: [] });
const adminRouter = AdminJSExpress.buildRouter(admin);

const server = new Server({ port: 3000 });
server.mountExpressRouter('/admin', adminRouter);
server.listen();

Using Express Middleware

Convert Express middleware to Balda middleware with useExpress:

import { Server } from 'balda-js';
import helmet from 'helmet';
import compression from 'compression';

const server = new Server({ port: 3000 });

// Mount middleware at root
server.useExpress(helmet());

// Mount middleware at specific path
server.useExpress('/api', compression());

server.listen();

API Reference

server.useExpress(middleware)

Mount Express middleware or router at the root path.

server.useExpress(someExpressMiddleware);
server.useExpress(someExpressRouter);

server.useExpress(path, middleware)

Mount Express middleware or router at a specific path.

server.useExpress('/admin', adminRouter);
server.useExpress('/api', apiMiddleware);

server.mountExpressRouter(basePath, router)

Directly mount an Express router, extracting all routes.

server.mountExpressRouter('/admin', adminJsRouter);

server.expressMiddleware(middleware)

Convert an Express middleware to a Balda-compatible middleware (ServerRouteMiddleware) for use with server.use().

Returns: ServerRouteMiddleware - A Balda-native middleware function

const baldaMiddleware = server.expressMiddleware(someExpressMiddleware);
server.use(baldaMiddleware);

Low-Level Functions

These functions are exported for advanced use cases but should typically be accessed via the server instance:

import {
expressMiddleware,
expressHandler,
} from 'balda-js';

// Convert Express middleware → Balda middleware (ServerRouteMiddleware)
const baldaMw = expressMiddleware(someExpressMiddleware);

// Convert Express handler → Balda handler (ServerRouteHandler)
const baldaHandler = expressHandler(someExpressHandler);
Recommended Approach

Use the server instance methods instead of standalone functions:

const server = new Server({ port: 3000 });

// ✅ Preferred: Use server methods
server.mountExpressApp(expressApp);
server.mountExpressApp(expressApp, '/api/v1');
server.mountExpressRouter('/admin', adminRouter);
server.useExpress(someExpressMiddleware);

// For middleware conversion
const baldaMw = server.expressMiddleware(someExpressMiddleware);

Common Use Cases

AdminJS Integration

import { Server } from 'balda-js';
import AdminJS from 'adminjs';
import AdminJSExpress from '@adminjs/express';
import * as AdminJSSequelize from '@adminjs/sequelize';

AdminJS.registerAdapter(AdminJSSequelize);

const admin = new AdminJS({
resources: [User, Post, Comment],
rootPath: '/admin',
});

const adminRouter = AdminJSExpress.buildRouter(admin);

const server = new Server({ port: 3000 });
server.mountExpressRouter('/admin', adminRouter);
server.listen();

Limitations

Important Limitations

The Express compatibility layer has some limitations you should be aware of:

Not Supported

FeatureStatusNotes
res.render()Template engines not supported
app.engine()View engines not available
app.set() / app.get() settingsExpress app settings not implemented
res.sendFile() streaming⚠️Works but no streaming callbacks
req.signedCookiesUse Balda's cookie plugin instead
Express sub-appsNested app.use(app) not supported
Express error middleware⚠️4-argument (err, req, res, next) partially supported
res.format()⚠️Returns empty, content negotiation not implemented
Trust proxy inheritanceUse Balda's trustProxy plugin

Partial Support

  • res.redirect() - Works, but always uses 302 unless status explicitly set
  • res.cookie() - Requires Balda's cookie plugin to be enabled
  • File uploads - Use Balda's fileParser plugin, not multer
  • Sessions - Use Balda's session plugin, Express session middleware may not work

For best results, use Balda native features when possible and reserve the Express compatibility layer for third-party libraries:

// ✅ Good: Use Express compat for third-party libraries
server.mountExpressRouter('/admin', adminJsRouter);

// ✅ Good: Use Balda native for your own routes
server.get('/api/users', (req, res) => {
res.json({ users: [] });
});

// ❌ Avoid: Don't use Express compat for simple middleware
// server.useExpress(cors()); // Use Balda's cors plugin instead
server.use(cors({ origin: '*' })); // Native Balda

Troubleshooting

HTML Not Rendering

If HTML appears as raw text, the Content-Type header may not be set. The adapter auto-detects HTML starting with <!DOCTYPE or <html>, but you can explicitly set it:

// In Express handler
res.type('text/html').send(htmlContent);

Middleware Not Executing

Ensure Express routers are mounted before calling server.listen():

const server = new Server({ port: 3000 });

// ✅ Correct: Mount before listen
server.mountExpressRouter('/admin', adminRouter);
server.listen();

// ❌ Wrong: Mounting after listen won't work correctly

Cookie/Session Issues

Enable Balda's cookie plugin for Express middleware that uses cookies:

const server = new Server({
port: 3000,
plugins: {
cookie: {}, // Enable cookie parsing
},
});

Runtime Support

The Express compatibility layer works across all Balda-supported runtimes:

RuntimeSupport
Node.js✅ Full
Bun✅ Full
Deno✅ Full

Note: Some Express middleware may have runtime-specific dependencies that only work in Node.js.