mrkeyoor.com_
Wed 23 Sept 00:35 UTC
npmWeb Backendupdated 22 Sept 2026

swagger-ui-express review

swagger-ui-express 5.0.1 mounts Swagger UI and an OpenAPI document on an Express route. Its serve middleware delivers the Swagger UI assets; setup() writes an initialization page from an in-memory document or browser-reachable spec URL. It also supports multiple documents, explorer mode, custom CSS or JavaScript, and request-specific documents. The current npm release only bumps dependencies. It does not generate an OpenAPI file, validate traffic, protect the docs route, or parse YAML. Our browser bundle attempt failed, which matches server middleware that should stay in Node.

Verdict

swagger-ui-express 5.0.1 installed 68 packages and 16 MB in 3.4 seconds with 0 audit findings, giving Express teams a short path to Swagger UI at a noticeable dependency cost. Pin swagger-ui-dist, secure the route, and add separate validation if the OpenAPI document must govern traffic.

We installed it

Lab card: what happened when we installed swagger-ui-expressScreenshot of swagger-ui-express documentation
Install✓ · 3.4s68 packages on disk · 16 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does swagger-ui-express install cleanly?

Yes. In a fresh container with an empty cache, npm install swagger-ui-express finished in 3 seconds, leaving 68 packages and 16 MB on disk. npm audit reported no known vulnerabilities.

Can swagger-ui-express run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does swagger-ui-express work with both ESM and CommonJS?

Yes. Both import 'swagger-ui-express' and require('swagger-ui-express') worked in Node 22 in our run. The package is published as CommonJS.

Does swagger-ui-express include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

swagger-ui-express or @scalar/express-api-reference: which should you use?

@scalar/express-api-reference: Use it for Scalar's Express-hosted API reference and integrated client experience. swagger-ui-express 5.0.1 installed 68 packages and 16 MB in 3.4 seconds with 0 audit findings, giving Express teams a short path to Swagger UI at a noticeable dependency cost.

When should you not use swagger-ui-express?

The server does not use Express. The exported values are Express middleware and do not provide a framework-neutral HTTP adapter.

API stability4/5serve, setup(), and serveFiles() have kept the same middleware arrangement through several major lines, and Express 5 support arrived without replacing that model. Stability is weaker below the adapter: swagger-ui-dist uses an unbounded >=5.0.0 range, so its assets and client behavior can move under a fixed 5.0.1 install unless the lockfile or package override constrains them. The unpublished 5.0.2 GitHub tag also makes repository and npm versions disagree.
Docs4/5The README includes complete examples for an Express app and Router, explorer mode, Swagger UI configuration, custom CSS and JavaScript, URL and YAML input, per-request documents, multiple instances, swagger-jsdoc, and a downloadable spec route. It also warns readers to pin swagger-ui-dist. Missing operational guidance lowers the score: access control, Content Security Policy, proxy trust, TypeScript declarations, and the difference between displaying and enforcing a contract are left to the integrator.
Maintenance2/5npm's latest is 5.0.1 from May 31, 2024, described only as a dependency bump. GitHub shows 1,497 stars, 54 open issues and pull requests, an unarchived repository, and its last push on January 25, 2025. A 5.0.2 tag exists on GitHub from that day but is not the npm latest version. The adapter can remain useful without frequent changes, though this publication mismatch and the open queue point to limited maintainer attention.
Ecosystem5/5npm counted 4,709,374 downloads in the latest completed week. The package accepts Express 4 and 5, consumes documents from swagger-jsdoc or any other OpenAPI generator, and delegates rendering to the widely used swagger-ui-dist project. External TypeScript definitions are available, and many Express examples use the same serve/setup pairing. Its ecosystem is broad for documentation display, but request validation, generation, and authorization remain separate tool choices.

Use it if

  • An Express 4 or 5 service already has an OpenAPI document and needs an interactive reference route.
  • The API team wants Swagger UI's request console served by the same host as the application.
  • Several specs need separate routes or an explorer dropdown backed by browser-accessible URLs.
  • Documentation needs a custom title, favicon, stylesheet, or trusted client script without maintaining a separate frontend.
Skip it if

Setup reality

We installed swagger-ui-express 5.0.1 in a fresh Node 22 Bookworm sandbox. npm finished in 3.4 seconds and left 68 packages using 16 MB. The adapter itself is 36 KB unpacked, declares 1 direct dependency and 1 peer, and returned 0 npm audit findings. It is CommonJS with no exports map or bundled TypeScript declarations; require() and ESM import both worked through Node interop. Our esbuild browser build failed, as expected for Express server middleware.

Install Express separately, then mount swaggerUi.serve and swaggerUi.setup(spec) on the same route. YAML needs a separate parser and startup error handling. The direct swagger-ui-dist range is >=5.0.0, and the README explicitly recommends a lockfile or a pinned version. Without that control, the browser UI can change even while swagger-ui-express stays at 5.0.1. TypeScript users also need the external @types package and compatible CommonJS interop settings.

A remote url or urls setting is fetched by the user's browser after the HTML loads. Cross-origin specs therefore need CORS and must be reachable from the client network, not only from the Express process. For 2 independent UIs, use serveFiles(document, options) at each route. Request-specific content goes on req.swaggerDoc; create a fresh top-level object instead of mutating one shared spec with host data from concurrent requests.

The package adds no authentication and leaves Swagger UI's Try it out feature available according to the supplied configuration. Put authorization middleware before both assets and HTML, and remove internal operations from any public document. customJs and customJsStr execute in the page, so use only trusted code and account for script-src in Content Security Policy. Version 5.0.1 contains only dependency updates, while the repository's 5.0.2 tag has not become npm latest.

Patterns

Serve one OpenAPI document mount-json-document

const express = require('express');
const swaggerUi = require('swagger-ui-express');
const openapi = require('./openapi.json');

const app = express();
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(openapi));

Both asset and HTML middleware share /api-docs. Put access control before them when the document is private.

Attach Swagger UI to an Express Router mount-on-router

const router = require('express').Router();
router.use('/api-docs', swaggerUi.serve);
router.get('/api-docs', swaggerUi.setup(openapi));

Use router.use() for static assets and router.get() for the generated index handler.

Authenticate every documentation request protect-documentation

app.use(
  '/api-docs',
  requireInternalUser,
  swaggerUi.serve,
  swaggerUi.setup(openapi),
);

The package has 0 authorization features. Your middleware must run before the UI assets and document page.

Parse a YAML document before listening load-yaml-at-startup

const fs = require('node:fs');
const YAML = require('yaml');

const source = fs.readFileSync('./openapi.yaml', 'utf8');
const openapi = YAML.parse(source);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(openapi));

YAML parsing is outside swagger-ui-express. Let parse errors fail startup rather than serving an empty page.

Set Swagger UI behavior configure-ui-client

const options = {
  explorer: true,
  swaggerOptions: {
    validatorUrl: null,
    displayRequestDuration: true,
    persistAuthorization: false,
  },
};

explorer belongs at the wrapper level. Swagger UI runtime settings belong inside swaggerOptions.

Set title, favicon, and CSS brand-documentation-page

const options = {
  customSiteTitle: 'Payments API',
  customfavIcon: '/assets/favicon.ico',
  customCss: '.swagger-ui .topbar { display: none }',
  customCssUrl: '/assets/api-docs.css',
};

The browser loads customCssUrl. Express must serve that URL and the page's style-src policy must permit it.

Publish the spec as a separate endpoint load-browser-spec-url

const options = { swaggerOptions: { url: '/api-docs/openapi.json' } };

app.get('/api-docs/openapi.json', (_req, res) => res.json(openapi));
app.use('/api-docs', swaggerUi.serveFiles(null, options), swaggerUi.setup(null, options));

The browser fetches the URL after page load. Cross-origin URLs need client-visible networking and CORS headers.

List several documents in explorer offer-spec-dropdown

const options = {
  explorer: true,
  swaggerOptions: {
    urls: [
      { name: 'Public API', url: '/specs/public.json' },
      { name: 'Admin API', url: '/specs/admin.json' },
    ],
  },
};

explorer: true is required for the selector, and the browser fetches each selected URL.

Keep public and admin specs separate mount-independent-docs

app.use('/public-docs', swaggerUi.serveFiles(publicSpec), swaggerUi.setup(publicSpec));
app.use('/admin-docs', requireAdmin, swaggerUi.serveFiles(adminSpec), swaggerUi.setup(adminSpec));

Use serveFiles() for each document. Sharing swaggerUi.serve across differently initialized UIs can mix configuration assets.

Set the server URL from a request build-request-specific-document

app.use('/api-docs', (req, _res, next) => {
  req.swaggerDoc = {
    ...openapi,
    servers: [{ url: `${req.protocol}://${req.get('host')}` }],
  };
  next();
}, swaggerUi.serveFiles(), swaggerUi.setup());

Create a new object per request. Express trust proxy settings determine whether req.protocol reflects the public scheme.

Load one controlled client script inject-trusted-script

const options = { customJs: '/assets/swagger-custom.js' };
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(openapi, options));

customJs executes in the page. Restrict it to code you own and permit its URL in script-src.

Pass swagger-jsdoc output to the UI display-generated-spec

const spec = swaggerJSDoc({
  definition: { openapi: '3.1.0', info: { title: 'Orders API', version: '1.0.0' } },
  apis: ['./src/routes/**/*.js'],
});
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(spec));

swagger-jsdoc creates the document; swagger-ui-express only renders it. Contract validation needs another package.

Alternatives

PackageRegistryPick it when
@scalar/express-api-referencenpmUse it for Scalar's Express-hosted API reference and integrated client experience.
redoc-expressnpmUse it when a readable reference document matters more than an in-page request console.
swagger-uinpmUse the UI directly when you control a separate frontend and do not need an Express adapter.
koa2-swagger-uinpmUse it for the same Swagger UI job in a Koa application.

More web backend guides

urllib3 · requests · ws · anyio · httpx · undici · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.