Inertia.js v3 is now an official Goravel package. Server-driven SPAs with Vue 3 or React, Vite HMR, SSR with CSR fallback — the Laravel DX, in Go.
If you come from Laravel, you know the feeling: Inertia.js lets you build a real single-page app — Vue or React on the frontend — without building an API. No REST endpoints, no client-side routing, no token juggling. Your controllers return pages, props flow in, and it just works.
Go never had that experience for a full-stack framework. Now it does.
goravel/inertia is the official Inertia.js v3 adapter for Goravel, the Go framework with Laravel's architecture and conventions. It started as a community package and has just been adopted into the Goravel organization.
This is what a controller looks like:
func (c *HomeController) Index(ctx http.Context) http.Response {
return facades.Inertia().Render(ctx, "Home", map[string]any{
"message": "Hello from Goravel + Inertia",
})
}
That's it. Home is a Vue or React component. message arrives as a prop. No serializers, no fetch calls, no route duplication.
From zero to a running SPA in four commands
go run . artisan package:install github.com/goravel/inertia
go run . artisan inertia:install # Vue 3 (default)
# go run . artisan inertia:install --stack=react # or React 19
npm install
npm run dev # then, in another shell: go run .
The inertia:install command scaffolds everything: config/inertia.go, the root template, a full demo app (Home / Feed / Contact / About) with its Go controllers, the HandleInertiaRequests middleware, vite.config.ts and package.json. It even wires routes/web.go for you.
Open http://localhost:3000 and you have a working SPA with hot-module reload.
The parts that usually hurt — already solved
Inertia v3 props: deferred, optional, merge, infinite scroll
The full v3 prop toolbox is available from your controllers:
func (c *DashboardController) Index(ctx http.Context) http.Response {
// Loaded after first paint — the page renders instantly,
// stats stream in behind it (<Deferred> on the client).
facades.Inertia().Defer(ctx, "stats", func() any { return loadStats() })
// Client-side "load more" pagination: new items merge into the list.
facades.Inertia().Merge(ctx, "posts", func() any { return nextPage(ctx) })
return facades.Inertia().Render(ctx, "Dashboard", nil)
}
Defer, Optional, Always, Merge, DeepMerge, Prepend, Once, Scroll — same semantics as the Laravel adapter.
Shared props, the Laravel way
inertia:install scaffolds app/http/middleware/handle_inertia_requests.go — the Go analogue of Laravel's HandleInertiaRequests::share():
func share(ctx http.Context) map[string]any {
return map[string]any{
"appName": facades.Config().GetString("app.name"),
"auth": map[string]any{
"user": authUser(ctx),
},
}
}
Runs once per request, context-aware, and you own the file.
Flash messages & validation errors — bridged automatically
Fail a validation, flash the errors, redirect back. The package mirrors them into props.errors and props.flash on the next request — exactly where useForm() expects them:
func (c *ContactController) Store(ctx http.Context) http.Response {
validator, err := ctx.Request().Validate(map[string]any{
"email": "required|email",
})
if err != nil || validator.Fails() {
facades.Inertia().FlashErrors(ctx, validator.Errors())
return facades.Inertia().Redirect(ctx, "/contact")
}
ctx.Request().Session().Flash("success", "Saved!")
return facades.Inertia().Redirect(ctx, "/contact")
}
Redirect is Inertia-aware too: it answers 303 on PUT/PATCH/DELETE so the browser re-fetches with GET, mirroring inertia-laravel.
Vite: dev and prod, no configuration
-
npm run devwritespublic/hot→ assets load from the dev server with HMR (React Fast Refresh preamble included for the React stack). -
npm run buildemits hashed assets + manifest → the{{ vite "resources/js/app.ts" }}template helper switches automatically. - The Inertia asset version is derived from the manifest hash, so every deploy busts stale clients — no manual version bumps.
SSR that degrades gracefully
npm run build:ssr && npm run ssr # SSR server on :13714
INERTIA_SSR=true go run .
Here's my favorite detail: if the SSR server is down or unreachable, the adapter falls back to client-side rendering instead of serving a blank page. A warning lands in the logs; your users never notice.
Design notes, for the curious
- Built on
petaki/inertia-go(MIT) for the wire protocol, wrapped in Goravel idioms: acontracts.Inertiainterface, a service provider, a facade, generated mocks. - Your app depends only on the contract — the engine underneath can evolve without breaking you.
- Session, validation, routing and middleware integrate with Goravel v1.18's native modules.
- Test suite runs with
-race, CI on every push, MIT licensed.
Requirements
| Go | 1.26+ |
| Goravel | v1.18+ |
| Node | 18+ (Vite frontend) |
Try it, break it, tell us
The package just moved into the Goravel organization and this is its first official release — feedback is gold right now:
- ⭐ Repo: github.com/goravel/inertia
- 🐛 Issues and feature requests welcome
- 💬 Goravel community: github.com/goravel/goravel/discussions
If you've been waiting for a reason to try Go for full-stack web work without giving up the Laravel developer experience — this is it.

Top comments (0)