Skip to main content

Server Setup

Unchained Engine supports both Express and Fastify as HTTP server frameworks. Both provide identical functionality through the connect() function from @unchainedshop/api.

Quick Comparison

AspectExpressFastify
PerformanceGoodBetter (2-3x faster)
Async SupportCallback-basedNative async/await
Plugin SystemMiddlewareHooks and decorators
TypeScriptGoodExcellent
EcosystemLargestGrowing
RecommendedTeams familiar with ExpressNew projects

Fastify is the recommended choice for new projects. It's used by the default kitchensink example.

import Fastify from 'fastify';
import { startPlatform } from '@unchainedshop/platform';
import { connect, unchainedLogger } from '@unchainedshop/api/fastify';
import defaultModules, { registerAllPlugins } from '@unchainedshop/plugins/presets/all.js';

registerAllPlugins();

const fastify = Fastify({
loggerInstance: unchainedLogger('fastify'),
disableRequestLogging: true,
trustProxy: true,
});

const platform = await startPlatform({
modules: defaultModules,
});

connect(fastify, platform, {
allowRemoteToLocalhostSecureCookies: process.env.NODE_ENV !== 'production',
adminUI: true,
});

await fastify.listen({
host: '::',
port: process.env.PORT ? parseInt(process.env.PORT) : 3000,
});

Express Setup

import express from 'express';
import http from 'node:http';
import { startPlatform } from '@unchainedshop/platform';
import { connect } from '@unchainedshop/api/express';
import defaultModules, { registerAllPlugins } from '@unchainedshop/plugins/presets/all.js';

registerAllPlugins();

const app = express();
const httpServer = http.createServer(app);

const platform = await startPlatform({
modules: defaultModules,
});

connect(app, platform, {
allowRemoteToLocalhostSecureCookies: process.env.NODE_ENV !== 'production',
});

await httpServer.listen({ port: process.env.PORT || 3000 });

Connect Options

Both adapters accept the same options in the third argument:

connect(server, platform, {
// Allow secure cookies over HTTP in development (blocked in production)
allowRemoteToLocalhostSecureCookies: boolean,

// Enable the Admin UI at the root path or configure with prefix
adminUI: boolean | { prefix: string },

// AI chat configuration (requires OpenAI-compatible provider)
chat: { model: ChatModel, imageGeneration?: ImageModel },

// OIDC/OAuth authentication configuration
authConfig: AuthConfig,

// Trust X-Forwarded-* headers from reverse proxy
trustProxy: boolean,
});

Key Differences

HTTP Server Creation

Express requires manually creating an HTTP server, while Fastify handles it internally:

// Express - manual HTTP server
const app = express();
const httpServer = http.createServer(app);
await httpServer.listen({ port: 3000 });

// Fastify - built-in server
const fastify = Fastify({ trustProxy: true });
await fastify.listen({ host: '::', port: 3000 });

Logger Integration

// Express - use createLogger from @unchainedshop/logger
import { createLogger } from '@unchainedshop/logger';
const logger = createLogger('app');

// Fastify - use unchainedLogger wrapper
import { unchainedLogger } from '@unchainedshop/api/fastify';
const fastify = Fastify({
loggerInstance: unchainedLogger('fastify'),
});

Adding Custom Middleware

// Express - standard middleware
app.use('/api/custom', (req, res) => {
res.json({ hello: 'world' });
});

// Fastify - route registration
fastify.route({
method: 'GET',
url: '/api/custom',
handler: async (request, reply) => {
return { hello: 'world' };
},
});

Admin UI

Both adapters support serving the Admin UI. Enable it via the adminUI option:

// Enable at root path
connect(server, platform, { adminUI: true });

// Enable with custom prefix
connect(server, platform, { adminUI: { prefix: '/admin' } });

OIDC Authentication

For enterprise authentication with external identity providers, pass the authConfig option. See the OIDC example for a complete implementation.