Custom Web Server is compatible but no longer recommended. For extending Server capabilities, please refer to Custom Server. For migration guide, see Migrate to the New Version of Custom Server.
Modern.js encapsulates most server-side capabilities required by projects, typically eliminating the need for server-side development. However, in certain scenarios such as user authentication, request preprocessing, or adding page skeletons, custom server-side logic may still be necessary.
Modern.js provides two types of APIs to extend the Web Server: Middleware and Lifecycle Hooks.
Middleware and Hooks only take effect when users request page routes, and BFF routes won't pass through these APIs.
Developers can execute the pnpm run new
command in the project root directory to enable the "Custom Web Server" feature:
After executing the command, register the @modern-js/plugin-server
plugin in modern.config.ts
:
Once enabled, a server/index.ts
file will be automatically created in the project directory where custom logic can be implemented.
Modern.js supports adding rendering middleware to the Web Server, allowing custom logic execution before and after processing page routes.
For detailed API and more usage, see UnstableMiddleware.
We recommend using UnstableMiddleware instead of Hooks.
Modern.js provides Hooks to control specific logic in the Web Server. All page requests will pass through Hooks.
Currently, two types of Hooks are available: AfterMatch
and AfterRender
. Developers can implement them in server/index.ts
as follows:
Best practices when using Hooks:
For detailed API and more usage, see Hook.
Modern.js Server is continuously evolving to provide more powerful features. We have optimized the definition and usage of middleware and Server plugins. While the old custom Web Server approach is still compatible, we strongly recommend migrating according to this guide to fully leverage the advantages of the new version.
server/modern.server.ts
according to the new definition method.server/index.ts
to middleware or plugins, and update your code with reference to the differences between Context
and Next
.In the new version, the middleware handler type is Hono's MiddlewareHandler
, meaning the Context
type is Hono Context
. The differences from the old custom Web Server's Context
are as follows:
Differences between UnstableMiddleware Context and Hono Context:
UnstableMiddleware | Hono | Description |
---|---|---|
c.request |
c.req.raw |
Refer to HonoRequest raw documentation |
c.response |
c.res |
Refer to Hono Context res documentation |
c.route |
c.get('route') |
Get application context information. |
loaderContext.get |
honoContext.get |
After injecting data using c.set , consume in dataLoader: the old version uses loaderContext.get , refer to the new version in Plugin example |
Differences between Middleware Context
and Hono Context
:
UnstableMiddleware | Hono | Description |
---|---|---|
c.request.cookie |
c.req.cookie() |
Refer to Hono Cookie Helper documentation |
c.request.pathname |
c.req.path |
Refer to HonoRequest path documentation |
c.request.url |
- | Hono c.req.url provides the full request URL, calculate manually from URL |
c.request.host |
c.req.header('Host') |
Obtain host through header |
c.request.query |
c.req.query() |
Refer to HonoRequest query documentation |
c.request.headers |
c.req.header() |
Refer to HonoRequest header documentation |
c.response.set |
c.res.headers.set |
Example: c.res.headers.set('custom-header', '1') |
c.response.status |
c.status |
Example: c.status(201) |
c.response.cookies |
c.header |
Example: c.header('Set-Cookie', 'user_id=123') |
c.response.raw |
c.res |
Refer to Hono Context res documentation |
Hook Context is mostly consistent with Middleware Context, so we need to pay extra attention to the additional parts of different Hooks.
UnstableMiddleware | Hono | Description |
---|---|---|
router.redirect |
c.redirect |
Refer to Hono Context redirect documentation |
router.rewrite |
- | No corresponding capability provided at the moment |
template API | c.res |
Refer to Hono Context res documentation |
In Middleware and Hooks, the render function executes even without invoking next
.
In the new design, subsequent Middleware will only execute if the next
function is invoked.