Skip to main content

Server Setup

Unchained Engine supports both Express and Fastify as HTTP server frameworks, with identical functionality through the connect() function from @unchainedshop/api/express or @unchainedshop/api/fastify. Fastify is used by the default kitchensink example and recommended for new projects; the kitchensink-express example shows the Express equivalent.

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

registerAllPlugins();

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

const platform = await startPlatform({});

await 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 { registerAllPlugins } from '@unchainedshop/plugins/presets/all';

registerAllPlugins();

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

const platform = await startPlatform({});

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

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

Import the preset without a file extension (@unchainedshop/plugins/presets/all) — the package exports map appends .js itself. startPlatform({}) needs no modules argument for the built-in core modules.

Connect Options​

Both adapters accept the same options in the third argument:

await connect(server, platform, {
// Allow secure cookies over HTTP for development;
// connect() throws if this is enabled with NODE_ENV=production
allowRemoteToLocalhostSecureCookies: boolean,

// Serve the Admin UI: true, or an options object
adminUI: boolean | { prefix?: string; theme?: AdminUIThemeConfig; plugins?: AdminUIPluginConfig[] },

// AI chat endpoint (Vercel AI SDK model instances)
chat: { model: LanguageModel; imageGenerationTool?: { model: ImageModel; uploadUrl?: string } },

// OIDC/OAuth authentication configuration
authConfig: AuthConfig,

// Trust X-Forwarded-For / X-Real-IP headers from a reverse proxy
// (implied automatically when allowRemoteToLocalhostSecureCookies is set)
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 Routes​

// 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​

Enable the Admin UI via the adminUI option:

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

// Serve under a prefix
await connect(server, platform, { adminUI: { prefix: '/admin' } });

The options object also accepts theme (design token overrides) and plugins (custom Admin UI extensions) — see the kitchensink examples for a full configuration.

OIDC Authentication​

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