Server-side > Go
Inertia.js Go Adapter
An Inertia.js server-side adapter for Go. Visit inertiajs.com to learn more.
Installation
Install the package using the go get command:
go get github.com/petaki/inertia-go
Usage
1. Create new instance
url := "http://inertia-app.test" // Application URL for redirect
rootTemplate := "./app.gohtml" // Root template, see the example below
version := "" // Asset version
inertiaManager := inertia.New(url, rootTemplate, version)
Or create with embed.FS for root template:
import "embed"
//go:embed template
var templateFS embed.FS
// ...
inertiaManager := inertia.New(url, rootTemplate, version, templateFS)
2. Register the middleware
mux := http.NewServeMux()
mux.Handle("/", inertiaManager.Middleware(homeHandler))
3. Render in handlers
func homeHandler(w http.ResponseWriter, r *http.Request) {
// ...
err := inertiaManager.Render(w, r, "home/Index", nil)
if err != nil {
// Handle server error...
}
}
Or render with props:
// ...
err := inertiaManager.Render(w, r, "home/Index", map[string]any{
"total": 32,
})
//...
4. Server-side Rendering (Optional)
First, enable SSR with the url of the Node server:
inertiaManager.EnableSsrWithDefault() // http://127.0.0.1:13714/render
Or with custom url:
inertiaManager.EnableSsr("http://ssr-host:13714/render")
Or with the Vite dev server:
inertiaManager.EnableSsr("http://localhost:5173/__inertia_ssr")
You can also provide a custom *http.Client:
client := &http.Client{
Timeout: 10 * time.Second,
}
inertiaManager.EnableSsr("http://ssr-host:13714/render", client)
inertiaManager.EnableSsrWithDefault(client)
For more information, please read the official Server-side Rendering documentation on inertiajs.com.
Page Props
| Name | Method(s) | Evaluation | Full | Partial |
|---|---|---|---|---|
| Base | Share, WithProp, Render |
Eager | ✅ | ✅ if requested |
| Optional | WithOptionalProp |
Lazy | ❌ | ✅ if requested |
| Always | WithAlwaysProp |
Lazy | ✅ | ✅ always |
| Deferred | WithDeferredProp |
Lazy | ❌ deferred | ✅ if requested |
| Merge | WithMergeProp |
Lazy | ✅ | ✅ if requested |
| Deep Merge | WithDeepMergeProp |
Lazy | ✅ | ✅ if requested |
| Prepend | WithPrependProp |
Lazy | ✅ | ✅ if requested |
| Scroll | WithScrollProp |
— | ✅ metadata | ✅ metadata |
| Once | WithOnceProp, WithOnce |
Lazy | ✅ | ✅ if requested |
| Error | WithErrorProp |
Eager | ✅ always | ✅ always |
WithOncecan be combined with Deferred, Merge, Deep Merge, Prepend, and Optional props.WithOncePropandWithOnceprops are excluded when listed in theX-Inertia-Except-Once-Propsheader.WithScrollPropadds scroll metadata to the page response for infinite scroll support.WithErrorProperrors are merged with any inlineerrorsmap passed toRender.
Page Settings
| Name | Method(s) | Evaluation | Full | Partial |
|---|---|---|---|---|
| Flash | WithFlash |
Eager | ✅ | ✅ |
| Clear History | WithClearHistory |
Eager | ✅ | ✅ |
| Encrypt History | WithEncryptHistory |
Eager | ✅ | ✅ |
| Preserve Fragment | WithPreserveFragment |
Eager | ✅ | ✅ |
WithClearHistory,WithEncryptHistory, andWithPreserveFragmentare emitted only when set totrue.
Examples
The following examples show how to use the package.
Share a function with root template (globally)
inertiaManager.ShareFunc("asset", assetFunc)
<script src="{{ asset "js/app.js" }}"></script>
Share data with root template (globally)
inertiaManager.ShareViewData("env", "production")
{{ if eq .env "production" }}
...
{{ end }}
Share data with root template (context based)
ctx := inertiaManager.WithViewData(r.Context(), "meta", meta)
r = r.WithContext(ctx)
<meta name="description" content="{{ .meta }}">
Share a prop (globally)
inertiaManager.Share("title", "Inertia App Title")
Share a prop (context based)
func authenticate(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// ...
ctx := inertiaManager.WithProp(r.Context(), "authUserID", user.ID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
Optional prop (context based)
ctx := inertiaManager.WithOptionalProp(r.Context(), "extra", func() any {
return getExtra()
})
r = r.WithContext(ctx)
Always prop (context based)
ctx := inertiaManager.WithAlwaysProp(r.Context(), "notifications", func() any {
return getNotifications()
})
r = r.WithContext(ctx)
Deferred prop (context based)
ctx := inertiaManager.WithDeferredProp(r.Context(), "comments", func() any {
return getComments()
})
r = r.WithContext(ctx)
Deferred prop with group (context based)
ctx := inertiaManager.WithDeferredProp(r.Context(), "comments", func() any {
return getComments()
}, "my-group")
r = r.WithContext(ctx)
Merge prop (context based)
ctx := inertiaManager.WithMergeProp(r.Context(), "results", func() any {
return getResults()
})
r = r.WithContext(ctx)
Or with match on:
ctx := inertiaManager.WithMergeProp(r.Context(), "results", func() any {
return getResults()
}, "id")
r = r.WithContext(ctx)
Or with multiple nested match on paths:
ctx := inertiaManager.WithMergeProp(r.Context(), "complexData", func() any {
return getComplexData()
}, "users.data.id", "messages.uuid")
r = r.WithContext(ctx)
Deep merge prop (context based)
ctx := inertiaManager.WithDeepMergeProp(r.Context(), "settings", func() any {
return getSettings()
})
r = r.WithContext(ctx)
Or with match on:
ctx := inertiaManager.WithDeepMergeProp(r.Context(), "settings", func() any {
return getSettings()
}, "id")
r = r.WithContext(ctx)
Prepend prop (context based)
ctx := inertiaManager.WithPrependProp(r.Context(), "notifications", func() any {
return getNotifications()
})
r = r.WithContext(ctx)
Or with match on:
ctx := inertiaManager.WithPrependProp(r.Context(), "notifications", func() any {
return getNotifications()
}, "id")
r = r.WithContext(ctx)
Scroll prop (context based)
ctx := inertiaManager.WithScrollProp(r.Context(), "items", inertia.ScrollPageProp{
PageName: "page",
CurrentPage: 1,
NextPage: 2,
})
r = r.WithContext(ctx)
Once prop (context based)
ctx := inertiaManager.WithOnceProp(r.Context(), "plans", func() any {
return getPlans()
})
r = r.WithContext(ctx)
Once modifier (context based)
ctx := inertiaManager.WithMergeProp(r.Context(), "activity", func() any {
return getActivity()
})
ctx = inertiaManager.WithOnce(ctx, "activity")
r = r.WithContext(ctx)
Or with expiration:
expiresAt := time.Now().Add(24 * time.Hour).UnixMilli()
ctx := inertiaManager.WithDeferredProp(r.Context(), "permissions", func() any {
return getPermissions()
})
ctx = inertiaManager.WithOnce(ctx, "permissions", inertia.OncePageProp{ExpiresAt: &expiresAt})
r = r.WithContext(ctx)
Error prop (context based)
ctx := inertiaManager.WithErrorProp(r.Context(), "email", "Invalid email")
r = r.WithContext(ctx)
Or with multiple fields:
ctx := inertiaManager.WithErrorProp(r.Context(), "email", "Invalid email")
ctx = inertiaManager.WithErrorProp(ctx, "password", "Too short")
r = r.WithContext(ctx)
Flash (context based)
ctx := inertiaManager.WithFlash(r.Context(), map[string]any{
"success": "Item created successfully",
})
r = r.WithContext(ctx)
Clear history (context based)
ctx := inertiaManager.WithClearHistory(r.Context())
r = r.WithContext(ctx)
Encrypt history (context based)
ctx := inertiaManager.WithEncryptHistory(r.Context())
r = r.WithContext(ctx)
Preserve fragment (context based)
ctx := inertiaManager.WithPreserveFragment(r.Context())
r = r.WithContext(ctx)
Root template
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="css/app.css" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<script data-page="app" type="application/json">{{ marshal .page }}</script>
<div id="app"></div>
<script src="js/app.js"></script>
</body>
</html>
Root template with Server-side Rendering (SSR)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="css/app.css" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="favicon.ico">
{{ if .ssr }}
{{ raw .ssr.Head }}
{{ end }}
</head>
<body>
{{ if not .ssr }}
<script data-page="app" type="application/json">{{ marshal .page }}</script>
<div id="app"></div>
{{ else }}
{{ raw .ssr.Body }}
{{ end }}
<script src="js/app.js"></script>
</body>
</html>
Vite Integration
For Vite integration, check out the Usage with Inertia section in the petaki/support-go package.
Example Apps
Satellite
Vite /
Vue3
https://github.com/petaki/satellite
Homettp
Vite /
Vue3
https://github.com/homettp/homettp
Waterkube
Vite /
Vue3
https://github.com/waterkube/waterkube
Contributors
- @monstergron for logo (ArtStation)
Reporting Issues
If you are facing a problem with this package or found any bug, please open an issue on GitHub.
License
The MIT License (MIT). Please see License File for more information.