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
Maintainers
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-expressRequirements
- Express:
>=5.0.0is required for compatibility withrg-express. - Make sure you have Express v5 or higher installed.
- Install Express using
npm install express@^5.0.0,pnpm add express@^5.0.0oryarn 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.jsWith src Directory
├── package.json
├── src/
│ ├── routes/
│ └── app.ts or app.jsInside 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
autoSetupis used, a deprecation warning is logged, recommendingrouteGenIfEmpty. routeGenIfEmptyonly works if the project’s file extension (.ts,.js,.mjs, or.mts) matches the project type (TypeScript or JavaScript). For TypeScript projects, it requires.tsor.mtsfiles.- The
routesfunction 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 asrc/folder for a clean layout. Sincemain.tsis insrc/, setbaseDirto__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.tsEnable Auto-Generation: Set
routeGenIfEmpty: trueto create starter code for empty route files insrc/routes/—great for rapid prototyping:app.use(routes({ baseDir: __dirname, routeGenIfEmpty: true }));This generates templates for new routes, requiring
.tsfor TypeScript or.js/.mjsfor JavaScript.Avoid Deprecated Options: Skip
autoSetupandappinroutes(). Return aRouterand useapp.use()for modularity:const router = routes({ baseDir: __dirname }); app.use('/api', router); // Mount at /apiDebug with Logs: Use
rg-expresslogs (e.g., "✓ Ready in") to troubleshoot route scanning or auto-generation insrc/routes/.
📚 Bonus: What Happens Under the Hood?
Given baseDir = __dirname:
- Folder Scanning: Looks for a
routes/folder insidebaseDir. - File Matching: Matches files named
route.ts,route.js,route.mjs, orroute.mts. - Route Mapping: Converts folder structures to Express routes:
routes/product/route.ts→/productroutes/product/[id]/route.ts→/product/:idroutes/hello/[...slugs]/route.ts→/hello/{*slugs}
- Auto-Generation: If
routeGenIfEmptyistrue, 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.
