Creating Custom Transport Layer
Wails v3 allows you to provide a custom IPC transport layer while retaining all generated bindings and event communication. This enables you to replace the default HTTP fetch-based transport with WebSockets, custom protocols, or any other transport mechanism.
Overview
Section titled “Overview”By default, Wails uses HTTP fetch requests from the frontend to communicate with the backend via /wails/runtime. The custom transport API allows you to:
- Replace the HTTP transport with WebSockets, gRPC, or any custom protocol
- Maintain full compatibility with Wails code generation
- Keep all existing bindings, events, dialogs, and other Wails features
- Implement your own connection management, authentication, and error handling
Architecture
Section titled “Architecture”┌─────────────────────────────────────────────────┐│ Frontend (TypeScript) ││ - Generated bindings still work ││ - Your custom client transport │└──────────────────┬──────────────────────────────┘ │ │ Your Protocol (WebSocket/etc) │┌──────────────────▼──────────────────────────────┐│ Backend (Go) ││ - Your Transport implementation ││ - Wails MessageProcessor ││ - All existing Wails infrastructure │└─────────────────────────────────────────────────┘1. Implement the Transport Interface
Section titled “1. Implement the Transport Interface”Create a custom transport by implementing the Transport interface:
package main
import ( "context" "github.com/wailsapp/wails/v3/pkg/application")
type MyCustomTransport struct { // Your fields}
func (t *MyCustomTransport) Start(ctx context.Context, processor *application.MessageProcessor) error { // Initialize your transport (WebSocket server, gRPC server, etc.) // When you receive requests, call processor.HandleRuntimeCallWithIDs() return nil}
func (t *MyCustomTransport) Stop() error { // Clean up your transport return nil}2. Configure Your Application
Section titled “2. Configure Your Application”Pass your custom transport to the application options:
func main() { app := application.New(application.Options{ Name: "My App", Transport: &MyCustomTransport{}, // ... other options })
err := app.Run() if err != nil { log.Fatal(err) }}3. Modify Frontend Runtime
Section titled “3. Modify Frontend Runtime”If using a custom transport, you’ll need to modify the frontend runtime to use your transport instead of HTTP fetch. Implement RuntimeTransport interface that will be used to handle requests:
const { setTransport } = await import('/wails/runtime.js');
class MyRuntimeTransport { call(objectID: number, method: number, windowName: string, args: any): Promise<any> { // TODO: implement IPC call with your transport protocol
return resp; }}
const myTransport = new MyRuntimeTransport();setTransport(myTransport);- The default HTTP transport continues to work if no custom transport is specified
- Generated bindings remain unchanged - only the transport layer changes
- Events, dialogs, clipboard, and all other Wails features work transparently
- You’re responsible for error handling, reconnection logic, and security in your custom transport
- The WebSocket example provided is for demonstration and may need hardening for production use
API Reference
Section titled “API Reference”Transport Interface
Section titled “Transport Interface”type Transport interface { Start(ctx context.Context, messageProcessor *application.MessageProcessor) error // JSClient returns the JavaScript shim that the runtime injects into the // window so that frontend code can call into the transport. JSClient() []byte Stop() error}AssetServerTransport Interface (Optional)
Section titled “AssetServerTransport Interface (Optional)”For browser-based deployments or when you want to serve both assets and IPC through your custom transport, implement the AssetServerTransport interface:
type AssetServerTransport interface { Transport
// ServeAssets configures the transport to serve assets alongside IPC. // The assetHandler is Wails' internal asset server that handles all assets, // runtime.js, capabilities, flags, etc. ServeAssets(assetHandler http.Handler) error}When to implement this interface:
- Running the app in a browser instead of a webview
- Serving assets over HTTP alongside your custom IPC transport
- Building network-accessible applications
Example implementation:
func (t *MyTransport) ServeAssets(assetHandler http.Handler) error { mux := http.NewServeMux()
// Mount your IPC endpoint mux.HandleFunc("/my/ipc/endpoint", t.handleIPC)
// Mount Wails asset server for everything else mux.Handle("/", assetHandler)
// Start HTTP server t.httpServer.Handler = mux go t.httpServer.ListenAndServe()
return nil}When ServeAssets() is called, the assetHandler provides:
- All static assets (HTML, CSS, JS, images, etc.)
/wails/runtime.js- The Wails runtime library
See Also
Section titled “See Also”transport.go- Core transport interfaces and typesmessageprocessor.go- The underlying message processor that handles all Wails IPC