# railsware/js-routes: Rails Named Routes in JavaScript

> JsRoutes generates JavaScript functions from Rails named routes, keeping client-side URL construction aligned with the Rails application. It supports automatic development middleware, ESM output, TypeScript definitions, and custom route subsets.

**railsware/js-routes** — Brings Rails named routes to javascript

- Repository: https://github.com/railsware/js-routes
- Website: http://railsware.github.io/js-routes/
- Stars: 1,702 · Forks: 158
- Language: Ruby
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/railsware-js-routes

## Why JsRoutes belongs in a Rails and JavaScript stack

JsRoutes addresses a specific consistency problem: a Rails application can define paths in its route file, but JavaScript code still needs those paths for links, API requests, redirects, and other browser-side operations. Without generated helpers, frontend developers may duplicate path strings and parameter rules in JavaScript. Those copies can drift when a Rails route changes. JsRoutes instead treats Rails named routes as the source and emits JavaScript functions that accept route arguments and return the corresponding URL.

The target user is an engineer maintaining both a Rails backend and JavaScript code. The examples cover conventional application routes and namespaced REST routes. A Rails route named `root_path` becomes an imported JavaScript function, while a route such as `api_user_path` accepts a user identifier and query options. The latter is shown as:

```javascript
import { root_path, api_user_path } from './routes';

root_path() // => /
api_user_path(25, include_profile: true, format: 'json') // => /api/users/25.json?include_profile=true
```

This is route URL generation, not request routing in the browser. JsRoutes does not describe components, intercept navigation, or maintain browser history. Its responsibility stops at producing path helpers compatible with Rails naming and parameter conventions. That narrower boundary matters when choosing it for an application that already uses a separate client-side router or when multiple layers attempt to own URL construction.

## Generated route functions and ESM data flow

The basic data flow starts in `config/routes.rb`. JsRoutes reads the Rails route definitions, converts named routes into JavaScript exports, and writes the result to `app/javascript/routes.js`. In the basic setup, middleware handles regeneration during development, while a Rake dependency causes the JavaScript build to refresh the route files. The README describes this as the recommended path for a simple Rails application because it combines automatic local updates with generated TypeScript definitions.

The generated module uses named ESM exports, so JavaScript imports only the helpers used by the importing file. The README also documents a shared-package mode for applications with many routes. In that mode, `JsRoutes.package!` creates the core utilities, and separate generated files can point to a common package with the `package` option. The documentation says this can help tree shaking, although it does not provide a bundle-size measurement or a claim that every application will improve.

For applications that do not want one global route file, the low-level API can filter routes and write separate outputs. An advanced middleware can generate application, admin, and API files with `include`, `exclude`, and `default_url_options`. The API example also renders route source and TypeScript definitions through a Rails controller. This gives teams a way to expose generated route data, but it also means route inclusion rules and output destinations become application configuration that must be kept correct.

## Quick Start installation and first JavaScript import

Add the Ruby gem to the application's `Gemfile`. The README gives no npm runtime installation because JsRoutes is installed as a Rails gem and generates JavaScript source.

```ruby
gem "js-routes"
```

Generate the middleware configuration with the Rails generator:

```sh
rails generate js_routes:middleware
```

For a manual installation, add the middleware to `config/environments/development.rb`. The documented configuration registers `JsRoutes::Middleware` with Rails' Rack middleware stack.

```ruby
config.middleware.use(JsRoutes::Middleware)
```

The generated `routes.js` and `routes.d.ts` are build outputs, so the quick-start instructions add both paths to `.gitignore`. The Rake dependency then ensures the JavaScript task invokes `js:routes`. For an application without jsbundling-rails, the documentation attaches `js:routes` to `assets:precompile` instead.

```ruby
task "javascript:build" => "js:routes"
task "assets:precompile" => "js:routes"
```

A real first use is to import the named helper from `routes` and call it where the application needs the URL:

```javascript
import {post_path} from '../routes';

alert(post_path(1))
```

The generated output is application-specific. It should define `post_path` if the Rails application has a corresponding named route. If an import is missing, the first checks are the route name, middleware execution, JavaScript build task, and output location. The README does not document a separate diagnostic command or rollback procedure.

## Webpacker ERB loading and its TypeScript constraint

The README marks the Webpacker ERB loader as legacy. It generates routes through an ERB file and relies on the `rails-erb-loader` npm package, so it suits an existing Webpacker configuration that is not moving to another build path. The generator installs the relevant setup:

```sh
./bin/rails generate js_routes:webpacker
```

A manual setup adds the loader package, removes any static `app/javascript/routes.js`, and creates `config/webpack/loaders/erb.js` with a rule for `.erb` files processed by `rails-erb-loader`.

```sh
yarn add rails-erb-loader
rm -f app/javascript/routes.js
```

```javascript
module.exports = {
  rules: [
    {
      test: /\.erb$/,
      enforce: "pre",
      loader: "rails-erb-loader",
    },
  ],
};
```

The Webpacker environment must then append that loader, and `app/javascript/routes.js.erb` must render `JsRoutes.generate()`. Consumers import from `routes.js.erb` rather than from the middleware-generated file.

```erb
<%= JsRoutes.generate() %>
```

```javascript
import {post_path} from 'routes.js.erb';

alert(post_path(2));
```

The explicit limitation is TypeScript. The README says automatic Webpacker updates are unavailable for definitions because the TypeScript compiler cannot be configured to understand `.erb` extensions. It also states that this setup does not support IDE autocompletion with TypeScript. Projects that need generated declarations should use the basic setup or the advanced definition APIs instead of treating the legacy loader as an equal substitute.

## Advanced route subsets, definitions, and shared files

The low-level interface supports applications that need more control than a single automatically maintained module. `JsRoutes.generate(options)` returns a route file as a string, `JsRoutes.generate!(file_name, options)` writes it to a selected path, and `JsRoutes.definitions!(file_name, options)` writes TypeScript definitions. These methods can be called directly or from ERB context.

The documented admin example disables the namespace and limits output to matching route names, then assigns the generated source to `AdminRoutes`. The Rails controller example returns both source and definitions as JSON after filtering for API helpers and applying `default_url_options`. Such an API is useful when route generation has to happen on demand rather than only through a local middleware refresh.

TypeScript generation has a specific compatibility boundary: definitions are available only when `module_type` is `ESM`, which the README calls the strongly recommended and default setting. Setting `module_type` to `DTS` changes a JsRoutes instance into a definition generator rather than a route-source generator. This is useful in a custom pipeline, but it means the build process must explicitly request routes and declarations in the required formats.

The shared-package mode introduces another dependency edge. Generated route files refer to `./router.js`, so changing the package location can break imports across all generated subsets. The repository documents include and exclude patterns, but it does not document conflict handling between filters, tests that enumerate edge cases, or automatic rollback if one file succeeds and another fails.

## Operational limits, alternatives, licensing, and upgrades

The clearest failure mode is stale or absent output when the build and generation steps are disconnected. Quick Start addresses this through middleware and a Rake dependency, while the Webpacker path uses an ERB loader. A team that invokes Rails generators or runs JavaScript without the documented task can receive an older file or no file. The README does not document an automated freshness check, so `app/javascript/routes.js` and `routes.d.ts` should be treated as derived artifacts rather than manually maintained sources.

JsRoutes may also be the wrong tool when URL construction belongs entirely to a separate client-side router, or when manually written helpers are easier to audit in a small frontend. That alternative does not derive helpers from `config/routes.rb`, so it removes middleware, generated files, and TypeScript synchronization at the cost of maintaining server route conventions in JavaScript. Another documented option is Sprockets, but the README labels that integration deprecated and not recommended for modern applications. The alternative relevant to this project is therefore architecture based: generate from Rails, or keep route builders explicitly in the frontend.

The gem is licensed under MIT. That identifies the repository's stated permission model, but this review does not interpret legal obligations or dependency licenses. Recent release history includes v2.4.1 on 2026-06-21, v2.4.0 on 2026-06-11, and v2.3.7 on 2026-04-30. The last push was on 2026-06-21, so the repository is not archived and its documented maintenance signal is recent. Upgrade cost includes reviewing generated module format, route filters, middleware behavior, build tasks, and TypeScript output rather than changing frontend call sites alone.

## Conclusion

JsRoutes is suited to Rails applications that call named routes from JavaScript and want route generation to follow the server-side route table, especially when automatic development refreshes, ESM output, or TypeScript definitions are useful. It is a poor fit for a non-Rails frontend that does not need compatibility with Rails route helpers, for a project seeking a client-side router with its own navigation model, or for an application unwilling to ignore generated files and regenerate route output after server-side changes. Teams evaluating it should first verify that the generated route names, parameters, defaults, module format, and browser bundle fit the existing Rails and JavaScript build process. For the current repository, the last push was on 2026-06-21 and v2.4.1 was released on 2026-06-21, so the upgrade baseline should be checked against that release before adopting its generated files.

## FAQ

### How do I install JsRoutes in a Rails application?

Add `gem "js-routes"` to the Rails `Gemfile`. The README then recommends running `rails generate js_routes:middleware` or adding `config.middleware.use(JsRoutes::Middleware)` to `config/environments/development.rb`.

### Does JsRoutes support TypeScript definitions?

Yes, but definitions require `module_type` to be set to `ESM`, which the README identifies as the default and strongly recommended setting. The Webpacker ERB automatic-update path does not support TypeScript definitions or IDE autocompletion because the compiler does not understand `.erb` extensions.

### Can JsRoutes generate separate files for admin and API routes?

Yes. The advanced API accepts `include` and `exclude` filters, while the documented middleware subclass generates separate application, admin, and API files with `JsRoutes.generate!`.

## Sources

- [License: MIT](https://github.com/railsware/js-routes/blob/main/LICENSE)
- [Project website](http://railsware.github.io/js-routes/)
- [railsware/js-routes on GitHub](https://github.com/railsware/js-routes)
- [README](https://github.com/railsware/js-routes/blob/main/README.md)
- [Releases](https://github.com/railsware/js-routes/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/railsware-js-routes
