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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@antennajs/adapter-hono

v2.0.0-beta.3

Published

The HonoJS adapter for Inertia.js

Downloads

47

Readme

@antennajs/adapter-hono

Integrate the InertiaJS protocol in your HonoJS backend.

Installation

# Using NPM
npm install @antennajs/adapter-hono

# Using Yarn
yarn add @antennajs/adapter-hono

# Using PNPM
pnpm add @antennajs/adapter-hono

Configuration

Import the createInertiaMiddleware function and create a middleware for your Hono application:

import { Hono } from 'hono'
import { createInertiaMiddleware } from '@antennajs/adapter-hono'

const app = new Hono()

app.use(
  '*',
  createInertiaMiddleware({
    view({ head, body }) {
      return `
        <!DOCTYPE html>
        <html>
          <head>
            <meta charset="utf-8" />
            <meta
              name="viewport"
              content="width=device-width, initial-scale=1.0, maximum-scale=1.0"
            />
            ${head.join('')}
            <script type="module" src="/app.js"></script>
          </head>
          <body>
            ${body}
          </body>
        </html>
        `
    },
  }),
)

You will then be able to access the current Inertia instance using Hono's context object to render components:

app.get('/', (ctx) => {
    return ctx.get('Inertia').render('Home')
})

// Or...

app.get('/', (ctx) => {
    return ctx.var.Inertia.render('Home')
})

// Or...
import { Inertia } from '@antennajs/adapter-hono'

app.get('/', (ctx) => {
    return Inertia.from(ctx).render('Home')
})

[!TIP] We also provide a way to access the current Inertia instance globally, so you don't need to use Hono's context to access it.

Learn more

Class-based Middleware

If you are used to or just like making middlewares with classes, there's also a way to do it:

import { Hono } from 'hono'
import { Middleware as InertiaMiddleware, type InertiaRenderProps } from '@antennajs/adapter-hono'

class Middleware extends InertiaMiddleware {
  public view(props: InertiaRenderProps): string {
    return ...
  }
}

const app = new Hono()

app.use(*, new Middleware().toMiddleware())

Calling toMiddleware() may seem redundant, however:

  1. Hono does not support class-based middlewares, so we need to cast it.
  2. We instruct Hono about context now containing our Inertia instance, so it has proper typing.

Defining a root element

By default, Inertia assumes that your application's root template has a root element with an id of app. If your application's root element needs a different id, you can provide it using the id property.

createInertiaMiddleware({
  rootElementId: 'my-app',
  // ...
})

[!CAUTION] This only modifies backend render behavior.

It is important to remember to also update the provided id for your client-side configuration.

If you have configured server-side rendering, you must also give it the same id.

Asset versioning

To enable automatic asset refreshing, you need to tell Inertia the current version of your assets. This must be a function that returns any arbitrary string (letters, numbers or a file hash), as long as it changes when your assets have been updated.

import type { HonoRequest } from 'hono'

createInertiaMiddleware({
  version(request: HonoRequest): string | null {
    return ...
  },
  // ...
})

// Or can be an async function as well.
createInertiaMiddleware({
  async version(request: HonoRequest): PromiseLike<string | null> {
    return ...
  },
  // ...
})

Sharing data

You can make pieces of data available to Inertia on every request. This is typically done outside your controllers. Shared data will be automatically merged with the page props provided in your controller.

import type { InertiaSharedProps } from "@antennajs/adapter-hono";

createInertiaMiddleware({
  share(): InertiaSharedProps {
    return {
      // Synchronously...
      'appName': ...,

      // Lazily...
      'auth.user': () => ...,
    }
  },
  // ...
})

You can also share data with the Inertia instance available in your request context later. For example, in a middleware:

import { createInertiaMiddleware } from '@antennajs/adapter-hono'

app.use('*', createInertiaMiddleware({ ... }), (ctx) => {
  const Inertia = ctx.get('Inertia')

  // Key-Value pair
  Inertia?.share('appName', ...)

  // Object syntax
  Inertia?.share({
    // Synchronously...
    'appName': ...,

    // Lazily...
    'auth.user': () => ...
  })
})

Customizing your root view

The view option of the middleware allow you to pass a function to generate your application shell using whatever methods you like, as well as it gives you access to useful information of the rendering cycle:

  • data: View-only data that is not passed down to the component. See Root template data
  • head: An array of strings containing the metadata of your page (Only populated when using SSR).
  • body: The compiled HTML body of your application.
  • request: Is the incoming Request object.

[!IMPORTANT] The request property is NOT an instance of HonoRequest, it is a native Request object.

createInertiaMiddleware({
  view({ data, head, body, request }): string {
    return `
      <!DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8" />
          <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0, maximum-scale=1.0"
          />
          ${head.join('')}
          <script type="module" src="/app.js"></script>
        </head>
        <body>
          ${body}
        </body>
      </html>
      `
  },
}),

Responses

Creating an Inertia response is straightforward. To get started, invoke the Inertia.render() method within your controller or route, providing the context of the request, the name of the JavaScript page component that you wish to render, as well as any props (data) for the component.

app.get('/events/:id', (ctx) => {
  const event = { ... }

  return ctx.get('Inertia')
    .render('Event/Show', {
      'event': {
        id: event.id,
        title: event.title,
        start_date: event.start_date,
        description: event.description
      }
    })
})

You can also add props using the with() method.

// Key-value pair
return ctx.get('Inertia')
  .render('Event')
  .with('event', { ... })

// Object syntax
return ctx.get('Inertia')
  .render('Event')
  .with({
    event: { ... }
  })

Root template data

Sometimes you may want to provide data to the root template that will not be sent to your JavaScript page / component. This can be achieved by invoking the withViewData method.

// Key-value pair
return ctx.get('Inertia')
  .render('Event', { event })
  .withViewData('meta', event.meta)

// Object syntax
return ctx.get('Inertia')
  .render('Event', { event })
  .withViewData({
    meta: event.meta,
  })

This data is injected into the data property of the view() method in your middleware:

createInertiaMiddleware({
  view({ data, head, body }): string {
    return ...
  },
}),

Maximum response size

Please refer to Inertia's Docs for more information.

Lazy data evaluation

For partial reloads to be most effective, be sure to use lazy data evaluation when returning props from your server routes or controllers. This can be achieved by wrapping all optional page data in a closure.

When Inertia performs a request, it will determine which data is required and only then will it evaluate the closure. This can significantly increase the performance of pages that contain a lot of optional data.

import { Inertia } from '@antennajs/adapter-hono'

function getUsers() {
  // ...
}

return ctx.get('Inertia')
  .render('Users/Index', {
    // ALWAYS included on first visit...
    // OPTIONALLY included on partial reloads...
    // ALWAYS evaluated...
    users: getUsers(),
  
    // ALWAYS included on first visit...
    // OPTIONALLY included on partial reloads...
    // ONLY evaluated when needed...
    users: () => getUsers(),
  
    // NEVER included on first visit...
    // OPTIONALLY included on partial reloads...
    // ONLY evaluated when needed...
    users: Inertia.lazy(() => getUsers()),
  })

[!TIP] You can also create lazy properties with the Inertia instance from context.

Both options give the same result. Use whichever you prefer 👍

ctx.get('Inertia').lazy(() => ...)

Globally available Inertia instance

Using Hono's context object to access the current Inertia instance is the best way to ensure your app remains compatible with all the platforms where Hono operates; but having to pass the context object around only to access the Inertia instance may be a little cumbersome.

For cases like this, we provide an implementation that enables accessing the current Inertia instance anywhere, as long as the Inertia middleware was executed first.

All you need to do is replace all your imports from @antennajs/adapter-hono to @antennajs/adapter-hono/async. No other changes are necessary!

Now, you can access the current Inertia instance globally:

import { Inertia, createInertiaMiddleware } from '@antennajs/adapter-hono/async'

function auth(ctx, next) {
    // Ensure user is correctly logged in, then...
    
    const user = ...
    
    Inertia.share('auth.user', user)
}

app.use(*, createInertiaMiddleware({ ... }), auth)

app.get('/', () => Inertia.render('Home'))

[!IMPORTANT] This implementation makes use of AsyncLocalStorage. Make sure your platform supports this feature.

Cloudflare Workers: Refer to Cloudflare Workers' Documentation to enable built-in compatibility of AsyncLocalStorage

[!TIP] You can still access Inertia from Hono's context object if required.

Server-side Rendering

This adapter allows you to define a function that can completely render your frontend application in the server without the need for an extra process to be running only to perform this operation.

[!NOTE] It should also be possible to use external rendering processes, the choice is yours.

createInertiaMiddleware({
  ssr(page) {
    return createInertiaApp(...)
  },
  // ...
})

Here are some implementation examples for different frameworks:

import { createInertiaApp } from '@inertiajs/vue3'
import { renderToString } from '@vue/server-renderer'
import { createSSRApp, h } from 'vue'

createInertiaMiddleware({
  ssr(page) {
    return createInertiaApp({
      page,
      render: renderToString,
      resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
        return pages[`./Pages/${name}.vue`]
      },
      setup({ App, props, plugin }) {
        return createSSRApp({
          render: () => h(App, props),
        }).use(plugin)
      },
    }),
  },
  // ...
})
import { createInertiaApp } from '@inertiajs/react'
import ReactDOMServer from 'react-dom/server'

createInertiaMiddleware({
  ssr(page) {
    return createInertiaApp({
      page,
      render: ReactDOMServer.renderToString,
      resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true })
        return pages[`./Pages/${name}.jsx`]
      },
      setup: ({ App, props }) => <App {...props} />,
    }),
  },
  // ...
})
import { createInertiaApp } from '@inertiajs/svelte'

createInertiaMiddleware({
  ssr(page) {
    return createInertiaApp({
      page,
      resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.svelte', { eager: true })
        return pages[`./Pages/${name}.svelte`]
      },
    }),
  },
  // ...
})

Client-side hydration

Instructions for official framework adapters can be found in Inertia's SSR Documentation. Otherwise, please consult your framework-specific adapter for more details.