{"id":15989,"library":"connect-history-api-fallback","title":"Connect History API Fallback Middleware","description":"connect-history-api-fallback is a robust middleware designed for Single Page Applications (SPAs) leveraging the HTML5 History API. It addresses the common challenge where direct access to client-side routes (e.g., `/about` or `/users/123`) or page refreshes result in a 404 \"Not Found\" error from the web server, as these paths do not correspond to physical files. The middleware intercepts such requests, identifies those that accept `text/html` and are not direct file requests (by default, paths containing a dot), and then rewrites the request URL to a specified index file, typically `/index.html`. This allows the SPA's client-side router to take over and render the correct view. The current stable version is 2.0.0. While there isn't a strict release cadence, updates generally address compatibility, performance, or new configuration options. Key differentiators include its configurable `index` path, powerful `rewrites` option supporting both static strings and dynamic functions based on request context, and fine-grained control over accepted HTML headers and dot-file handling. It seamlessly integrates with Connect and Express-based Node.js servers.","status":"active","version":"2.0.0","language":"javascript","source_language":"en","source_url":"ssh://git@github.com/bripkens/connect-history-api-fallback","tags":["javascript"],"install":[{"cmd":"npm install connect-history-api-fallback","lang":"bash","label":"npm"},{"cmd":"yarn add connect-history-api-fallback","lang":"bash","label":"yarn"},{"cmd":"pnpm add connect-history-api-fallback","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The library provides a default export, which is the middleware function itself. Named imports like `{ history }` will result in an undefined value or an error.","wrong":"import { history } from 'connect-history-api-fallback';","symbol":"history","correct":"import history from 'connect-history-api-fallback';"},{"note":"This is the standard CommonJS import pattern, widely used with Connect and Express applications.","symbol":"history","correct":"const history = require('connect-history-api-fallback');"},{"note":"For TypeScript users, type definitions are available via `@types/connect-history-api-fallback` to specify middleware options correctly. The library itself does not ship with built-in types.","symbol":"Options","correct":"import type { Options } from 'connect-history-api-fallback';"}],"quickstart":{"code":"const express = require('express');\nconst history = require('connect-history-api-fallback');\nconst path = require('path');\nconst app = express();\n\n// Create a simple 'public' directory with an 'index.html' for this example\n// You would typically have a build process generating these files.\n// For demonstration, ensure you have a 'public' directory with an index.html.\n// Example public/index.html content:\n// <!DOCTYPE html>\n// <html lang=\"en\">\n// <head><meta charset=\"UTF-8\"><title>SPA</title></head>\n// <body><h1>Welcome to SPA!</h1><p>Path: <span id=\"path\"></span></p>\n// <script>document.getElementById('path').innerText = window.location.pathname;</script>\n// <nav><a href=\"/\">Home</a> | <a href=\"/about\">About</a> | <a href=\"/users/1\">User</a></nav></body>\n// </html>\n\n// 1. Serve your static assets (like JS, CSS, images) first.\n// This ensures that actual files are served directly and not rewritten.\napp.use(express.static(path.join(__dirname, 'public')));\n\n// 2. Use the history API fallback middleware.\n// This middleware should come AFTER your static file server\n// but BEFORE any other catch-all routes.\napp.use(history({\n  // verbose: true, // Uncomment to log rewrite actions to the console\n  index: '/index.html', // Default in most cases, but good to be explicit\n  htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'] // Default in v2.0.0+\n}));\n\n// 3. Serve static assets again after the history fallback.\n// This is crucial: after a rewrite to `/index.html`, this `express.static` call\n// will actually serve the `index.html` file from your 'public' directory.\napp.use(express.static(path.join(__dirname, 'public')));\n\n// Optional: A final catch-all for anything not handled (e.g., actual 404s for non-SPA routes)\napp.get('*', (req, res) => {\n  res.status(404).send('Custom 404 - Resource Not Found on Server.');\n});\n\nconst PORT = process.env.PORT || 3000;\napp.listen(PORT, () => {\n  console.log(`Server listening on http://localhost:${PORT}`);\n  console.log('Navigate to /some-spa-route, then refresh the page.');\n  console.log('It should still serve index.html, handled by your client-side router.');\n});","lang":"javascript","description":"This quickstart demonstrates how to integrate `connect-history-api-fallback` with an Express server to handle client-side routing for a Single Page Application (SPA). It correctly places the middleware to serve static assets while ensuring that direct URL access or page refreshes on SPA routes gracefully fall back to `index.html`."},"warnings":[{"fix":"Remove the `logger` option from your configuration. If you need logging, set `verbose: true`.","message":"The `logger` option has been removed in version 2.0.0. Use the `verbose` option for console logging instead.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Review your `disableDotRule` configuration. If you previously relied on the `true` default, you might need to explicitly set `disableDotRule: true` to revert to rewriting paths with dots, though this is rarely recommended for static assets.","message":"The default value for `disableDotRule` changed from `true` to `false` in version 2.0.0. This means that by default, URLs containing a dot (e.g., `/main.js`, `/image.png`) will *not* be rewritten to the `index.html` file. This is generally the desired behavior to allow static assets to be served directly.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"No direct fix is usually required as the new default is more comprehensive. If you had a custom `htmlAcceptHeaders` array, ensure it still meets your application's needs.","message":"The default value for `htmlAcceptHeaders` changed in version 2.0.0 from `['text/html']` to `['text/html', 'application/xhtml+xml']`.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure all objects within your `rewrites` array specify both a `from` (RegExp) and `to` (string or function) property.","message":"When using the `rewrites` option, the `from` and `to` properties for each rewrite rule are now explicitly required in version 2.0.0.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Ensure `app.use(express.static('public'));` runs before `app.use(history());`, and consider running `app.use(express.static('public'));` again *after* `app.use(history());` to serve the rewritten `index.html`.","message":"The middleware must be placed correctly in your server's middleware chain. It should come *after* your static file serving middleware (e.g., `express.static`) for actual files, but *before* any other routing logic that should be bypassed for SPA routes. Crucially, if the middleware rewrites a path to `/index.html`, another static file serving middleware placed *after* `connect-history-api-fallback` is needed to actually serve that `index.html` file.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always provide the `index` option as an absolute HTTP path (e.g., `/default.html`). Do not use relative paths or file system paths here.","message":"The `index` option specifies an *HTTP request path* (e.g., `/index.html`), not a file system path. Downstream middleware (like `express.static`) is responsible for resolving this HTTP path to an actual file on disk.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure your API routes are defined *before* the `connect-history-api-fallback` middleware, or use the `rewrites` option to explicitly exclude API paths (e.g., `rewrites: [{ from: /\\/api\\/.*$/, to: (context) => context.parsedUrl.pathname }]`) to prevent them from being rewritten.","message":"API routes can be inadvertently rewritten to the `index.html` if they match the fallback criteria. This happens if the middleware is placed before your API router and your API paths do not contain dots or are not explicitly excluded by `rewrites`.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Ensure `connect-history-api-fallback` middleware is installed and correctly configured in your server.js, placed before any generic 404 handlers, and after the first static file serving middleware.","cause":"The web server attempted to locate a physical file at the SPA route (e.g., `/some/spa/route`) and failed, returning a 404 error, typically on page refresh or direct navigation.","error":"GET /some/spa/route 404 Not Found"},{"fix":"For CommonJS, use `const history = require('connect-history-api-fallback');`. For ESM, use `import history from 'connect-history-api-fallback';`.","cause":"The `connect-history-api-fallback` package exports a default function. This error usually occurs when attempting to destructure a named export that does not exist in CommonJS or incorrectly importing it as a named export in ESM.","error":"TypeError: history is not a function"},{"fix":"In v2.0.0+, `disableDotRule` defaults to `false`, which should prevent this. For earlier versions or if you've overridden it, ensure `disableDotRule` is explicitly `false` (or unset for v2+ default behavior). Also, ensure `express.static` (or equivalent) for your static assets is called *before* `app.use(history())` in your middleware chain.","cause":"Static assets with file extensions are being incorrectly rewritten by the middleware. This can be due to an incorrect `disableDotRule` setting (especially in v1), or the static file serving middleware being placed *after* the `connect-history-api-fallback` middleware.","error":"Requests for static assets (e.g., /app.js, /styles.css, /logo.png) are returning index.html content or 404s."},{"fix":"Place your API router middleware *before* `app.use(history())`. Alternatively, use the `rewrites` option to create a rule that explicitly allows API paths to pass through (e.g., `rewrites: [{ from: /\\/api\\/.*$/, to: (context) => context.parsedUrl.pathname }]`).","cause":"The `connect-history-api-fallback` middleware is intercepting and rewriting requests intended for your API endpoints.","error":"API calls are being rewritten, e.g., 'GET /api/data' shows '302 /index.html' in logs or returns HTML content."}],"ecosystem":"npm"}