Filesystem Routing
Both stacks build routes from the filesystem. The rule is the same on each: a file's location is its URL path. You never register routes by hand.
The rules
Efesto scans your routes directory and derives a path for each file:
- Folders are path segments.
routes/users/...lives under/users. indexmaps to its folder.routes/users/index.ts→/users.[param]becomes a route parameter.routes/users/[id].ts→/users/:id.- The extension is dropped, and which extension is scanned depends on
isProduction:.tsin development,.jsin production.
routes/
├── index.ts # / (root)
├── health.ts # /health
├── users/
│ ├── index.ts # /users
│ ├── [id].ts # /users/:id
│ └── [id]/
│ └── posts.ts # /users/:id/posts
└── products/
└── index.ts # /products
A mount prefix is prepended to all of these. With a prefix of /api/v1,
routes/users/[id].ts serves /api/v1/users/:id.
Edit the file path or prefix below to see the endpoint Efesto derives:
/api/v1/users/:idSetting the routes directory and prefix
- Express
- Bun/Elysia
The routes directory is options.absoluteDirRoutes (it accepts an array to scan
several). The mount prefix comes from where you mount the Express middleware:
app.use(
"/api/v1", // <- prefix
efesto({
authMiddleware,
errorMiddleware,
isProduction: process.env.NODE_ENV === "production",
options: {
absoluteDirRoutes: path.join(__dirname, "routes"), // <- routes dir
},
})
);
Read route parameters from req.params (e.g. req.params.id for [id].ts). Their
documented type is controlled by dynamicParameterType ("string" by default).
The routes directory is routesDir (also accepts an array). The prefix is prefix:
const app = efesto({
isProduction: process.env.NODE_ENV === "production",
routesDir: `${import.meta.dir}/routes`, // <- routes dir
prefix: "/api/v1", // <- prefix
});
A [id].ts file becomes the Elysia segment :id; read it from the typed params
context. Each route module uses relative paths internally ("/"), Efesto mounts
the module at the derived prefix for you.
What a file must export
- Express
- Bun/Elysia
A default export of a class extending BaseApiService. A file that doesn't export
one is not a valid route. See Creating Endpoints.
A default export of either a native Elysia instance or a class/instance
extending BaseApiService. Anything else is skipped with a warning in the console. See
Bun/Elysia.
Development vs production
The isProduction flag selects the file extension Efesto scans:
isProduction: false→ scans.ts(run from source withts-node/bun).isProduction: true→ scans the compiled.js(run from your build output).
Keep your build output mirroring your source tree so the derived paths stay identical between development and production.
Once a file is in place, define the route.