npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

rg-express

v1.0.4

Published

Welcome to the **rg-express** user guide! This document will help you get started with **rg-express**, a powerful route generator for Express that simplifies route management with file-based approach. Whether you're building APIs in TypeScript or JavaScri

Downloads

29

Readme

rg-express

User Guide

Welcome to the rg-express user guide! This document will help you get started with rg-express, a powerful route generator for Express that simplifies route management with file-based approach. Whether you're building APIs in TypeScript or JavaScript, rg-express provides a clean, intuitive way to organize your routes.


🚀 Introduction

rg-express is a route generator for Express, inspired by the modular routing style of Next.js. It helps developers manage routes with cleaner structure, reduced boilerplate, and optional middleware support — all by convention over configuration.

👉 Explore the Example Project (TypeScript)


📦 Installation

Install using your preferred package manager:

npm install rg-express
# or
pnpm add rg-express
# or
yarn add rg-express

Requirements

  • Express: >=5.0.0 is required for compatibility with rg-express.
  • Make sure you have Express v5 or higher installed.
  • Install Express using npm install express@^5.0.0 , pnpm add express@^5.0.0 or yarn add express@^5.0.0.
  • Older versions of Express are not supported.
  • For full functionality, ensure your Express version meets the requirement.

🗂️ Project Structure

Basic Setup

Without src Directory

├── package.json
├── routes/
├── app.ts or app.js

With src Directory

├── package.json
├── src/
│   ├── routes/
│   └── app.ts or app.js

Inside routes Folder

routes/
├── product/
│   ├── route.ts         → /product
│   └── [slug]/route.ts  → /product/:slug     → req.params.slug (string)
├── hello/
│   └── [...slugs]/route.ts → /hello/{*slugs}        → req.params.slugs (string[])

⚙️ Basic Usage (Detailed)

rg-express makes it easy to wire up your routes by pointing to a directory. It scans the routes/ folder, maps files to route paths, and either returns an Express Router or attaches routes directly to a provided Express app. The routes function supports both TypeScript and JavaScript projects and can automatically generate starter code for empty route files.


🔹 Option 1: Minimal Setup (String Path)

The simplest way—just provide the root directory where your routes/ folder exists. This returns an Express Router that you can attach to your app.

// app.ts

import express from 'express';
import { routes } from 'rg-express';

const app = express();

app.use(express.json());
app.use(routes(__dirname)); // Loads routes from __dirname/routes

app.listen(3000, () => {
  console.log('🚀 Server running at http://localhost:3000');
});

📁 Directory structure

project-root/
├── routes/
│   └── hello/
│       └── route.ts
└── app.ts

🧠 In routes/hello/route.ts:

export const GET = (req, res) => {
  res.send('Hello world!');
};

🔗 Access: http://localhost:3000/hello


🔹 Option 2: Full Configuration (Returning Router)

Provide a configuration object to customize behavior, returning a Router for manual attachment.

import express from 'express';
import { routes } from 'rg-express';

const app = express();

app.use(
  routes({
    baseDir: __dirname, // Required: where routes/ folder lives
    routeGenIfEmpty: true, // Optional: generates starter code for empty route files
  })
);

app.listen(3000, () => {
  console.log('✅ Server ready at http://localhost:3000');
});

🔹 New Feature: Custom Code Snippet for routeGenIfEmpty

You can now pass a custom code snippet or a function to routeGenIfEmpty. This allows you to define the default content for newly generated route files dynamically.

RouteGenIfEmpty Type Definition

type RouteGenIfEmpty =
  | boolean
  | {
      codeSnippet?: string;
      codeSnippetFn?: ((config: { spreadParams: string[], slugParams: string[], allParams: string[] })) => string;
    };

🔹 Option 3: Full Configuration (Attaching to App)

Provide an Express app in the configuration to automatically attach routes to it. This returns void as the routes are directly mounted.

import express from 'express';
import { routes } from 'rg-express';

const app = express();

routes({
  baseDir: __dirname,
  routeGenIfEmpty: true,
  app, // Attaches routes directly to this app instance
});

// or

app.use(
  routes({
    baseDir: __dirname,
    routeGenIfEmpty: {
      codeSnippet: `import { auth } from '@/middlewares/auth';
import { Request, Response } from 'express';

export const GET = [auth,async (req: Request, res: Response) => {
    res.send('hello');
}];`,
      codeSnippetFn: (filePath) =>
        `// Custom code for ${filePath}\nexport const GET = (req, res) => { res.send('Hello from ${filePath}'); };`,
    },
  })
);

app.listen(3000, () => {
  console.log('✅ Server ready at http://localhost:3000');
});

In this example, if a route file is empty, the specified codeSnippet or the result of codeSnippetFn will be written to the file.

⚠️ Note: Passing app is deprecated. Prefer returning a Router and using app.use() for better flexibility.


🔹 Option 4: Use Default Export

You can use the default rg function, which is equivalent to routes:

import express from 'express';
import rg from 'rg-express';

const app = express();

app.use(rg({ baseDir: __dirname }));

🔁 This is equivalent to:

import { routes } from 'rg-express';

app.use(routes({ baseDir: __dirname }));

RouteConfig interface options:

| Option | Type | Description | | ----------------- | ----------------------------- | ------------------------------------------------------------------------------- | | baseDir | string | Required. Root folder (where routes/ lives) | | routeGenIfEmpty | booleanor RouteGenIfEmpty | Auto-generates starter route if file is empty | | autoSetup | boolean | ⚠️ Deprecated in favor of routeGenIfEmpty | | app | Express | ⚠️ Deprecated. Attaches routes to the app (returns void). Omit to get a Router. |


Notes:

  • If autoSetup is used, a deprecation warning is logged, recommending routeGenIfEmpty.
  • routeGenIfEmpty only works if the project’s file extension (.ts, .js, .mjs, or .mts) matches the project type (TypeScript or JavaScript). For TypeScript projects, it requires .ts or .mts files.
  • The routes function validates file extensions, supporting only .ts, .js, .mjs, or .mts.

💡 Pro Tips

Maximize rg-express with these best practices for organizing and scaling your Express projects:

  • Use a src/ Structure: Place your entry point (e.g., src/main.ts) and routes (src/routes/*/**) in a src/ folder for a clean layout. Since main.ts is in src/, set baseDir to __dirname:

    import { routes } from 'rg-express';
    import express from 'express';
    
    const app = express();
    app.use(routes({ baseDir: __dirname }));

    📁 Example Structure:

    ├── src/
    │   ├── routes/
    │   │   ├── api/
    │   │   │   └── [id]/route.ts  → /api/:id
    │   │   └── hello/route.ts     → /hello
    │   └── main.ts
  • Enable Auto-Generation: Set routeGenIfEmpty: true to create starter code for empty route files in src/routes/—great for rapid prototyping:

    app.use(routes({ baseDir: __dirname, routeGenIfEmpty: true }));

    This generates templates for new routes, requiring .ts for TypeScript or .js/.mjs for JavaScript.

  • Avoid Deprecated Options: Skip autoSetup and app in routes(). Return a Router and use app.use() for modularity:

    const router = routes({ baseDir: __dirname });
    app.use('/api', router); // Mount at /api
  • Debug with Logs: Use rg-express logs (e.g., "✓ Ready in") to troubleshoot route scanning or auto-generation in src/routes/.


📚 Bonus: What Happens Under the Hood?

Given baseDir = __dirname:

  • Folder Scanning: Looks for a routes/ folder inside baseDir.
  • File Matching: Matches files named route.ts, route.js, route.mjs, or route.mts.
  • Route Mapping: Converts folder structures to Express routes:
    • routes/product/route.ts/product
    • routes/product/[id]/route.ts/product/:id
    • routes/hello/[...slugs]/route.ts/hello/{*slugs}
  • Auto-Generation: If routeGenIfEmpty is true, generates starter code for empty route files (only if the file extension matches the project type).
  • HTTP Methods: Supports standard HTTP methods (GET, POST, PUT, DELETE, etc.) exported from route files.
  • Performance Logging: Logs processing time and completion status using ProcessConsole.

⚙️ Route Configuration

Define HTTP handlers (GET, POST, etc.) by exporting them from route files. The routes function automatically maps these to the corresponding Express routes.

TypeScript Example

// routes/hello/route.ts

import type { Request, Response } from 'express';

/**
 * @api_endpoint: /hello/
 */
export const GET = (req: Request, res: Response) => {
  res.send('Hello from rg-express!');
};

// With middleware
export const POST = [
  checkAuth, // your middleware
  (req: Request, res: Response) => {
    res.send('Posted with middleware!');
  },
];

JavaScript Example

// routes/hello/route.js

module.exports.GET = (req, res) => {
  res.send('Hello from rg-express!');
};

const handlePost = (req, res) => {
  res.send('Posted with middleware!');
};

module.exports.POST = [checkAuth, handlePost];

📌 Dynamic Routing

[slug] – Single Dynamic Segment

// routes/abc/[slug]/route.ts

export const GET = (req: Request, res: Response) => {
  res.send(`Slug: ${req.params.slug}`);
};

✅ Matches: /abc/apple, /abc/banana


[...slugs] – Catch-All Segment

// routes/abc/[...slugs]/route.ts

export const GET = (req: Request, res: Response) => {
  res.send(`Slugs: ${req.params.slugs.join(', ')}`);
};

✅ Matches: /abc/a, /abc/a/b/c


🛡️ Smart Middleware Support

Export an array to include Express middlewares before your handler:

Example with Middlewares

// routes/user/route.ts

import { Request, Response, NextFunction } from 'express';
import { auth, isAdmin } from '../../middlewares';

const getUsers = (req: Request, res: Response) => {
  res.send('List of users');
};

const createUser = (req: Request, res: Response) => {
  res.send('User created!');
};

export const GET = [auth, getUsers];
export const POST = [auth, isAdmin, createUser];

Or define inline handlers:

// routes/user/route.ts

export const POST = [
  auth,
  isAdmin,
  (req: Request, res: Response) => {
    res.send('User created with inline handler');
  },
];

🧠 Dynamic Routes

[slug] → Single Param

// routes/blog/[slug]/route.ts

export const GET = (req: Request, res: Response) => {
  const { slug } = req.params;
  res.send(`You requested blog: ${slug}`);
};

🧱 JavaScript Support

// routes/hello/route.js

module.exports.GET = (req, res) => {
  res.send('Hello from JavaScript!');
};

module.exports.POST = [
  checkAuth,
  (req, res) => {
    res.send('Post with middleware in JS!');
  },
];

🧩 Middleware Utilities

You can create reusable middleware functions like:

// middlewares/index.ts

import { Request, Response, NextFunction } from 'express';

export const auth = (req: Request, res: Response, next: NextFunction) => {
  if (!req.headers.authorization) {
    return res.status(401).send('Unauthorized');
  }
  next();
};

export const isAdmin = (req: Request, res: Response, next: NextFunction) => {
  if (req.headers['x-role'] !== 'admin') {
    return res.status(403).send('Forbidden');
  }
  next();
};

Then reuse them smartly in routes.


🤝 Contributing

We welcome contributions! Please read the CONTRIBUTING.md for details on submitting PRs or reporting issues.


🎉 Conclusion

rg-express makes route organization in Express apps easier, cleaner, and more modular with built-in support for:

  • ✅ TypeScript & JavaScript (.ts, .js, .mjs, .mts)
  • 🧠 Dynamic routes
  • 🧩 Express-style middleware
  • ⚡ File-based auto-loading
  • 📝 Automatic starter code generation for empty files

Build smarter APIs, faster.