Documentation Index
Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
Use this file to discover all available pages before exploring further.
Embedding your frontend into the Go binary creates a single executable with no external dependencies.
How It Works
The //go:embed directive bundles files into the compiled binary:
package server
import (
"embed"
"io/fs"
"github.com/go-mizu/mizu"
"github.com/go-mizu/mizu/frontend"
)
//go:embed all:../../dist
var distFS embed.FS
func New() *mizu.App {
app := mizu.New()
// Extract 'dist' subdirectory
dist, _ := fs.Sub(distFS, "dist")
app.Use(frontend.WithFS(dist))
return app
}
Benefits
1. Single Binary Deployment
One file contains everything:
# Before (multiple files)
myapp/
βββ server
βββ dist/
β βββ index.html
β βββ assets/
β βββ ...
# After (single file)
server # Contains everything!
2. No External Dependencies
# Just copy the binary
scp ./bin/server user@server:/usr/local/bin/
# Run it
./server
3. Simpler Deployment
# Dockerfile
FROM scratch
COPY server /server
CMD ["/server"]
Single layer, minimal size.
4. Immutable Deployments
Frontend and backend versions always match.
Directory Structure
Before Embed
my-app/
βββ cmd/
β βββ server/
β βββ main.go
βββ app/
β βββ server/
β βββ app.go β Embed directive here
βββ dist/ β Built frontend
β βββ index.html
β βββ assets/
βββ go.mod
Embed Directive Location
// app/server/app.go
package server
//go:embed all:../../dist β Relative to this file
var distFS embed.FS
The path is relative to the .go file containing the directive.
Why Use fs.Sub?
The embed directive includes the directory name:
//go:embed all:../../dist
var distFS embed.FS
// distFS contains:
// dist/
// index.html
// assets/
Use fs.Sub to remove the prefix:
dist, _ := fs.Sub(distFS, "dist")
// dist contains:
// index.html
// assets/
Now index.html is at the root, as expected.
Complete Example
package server
import (
"embed"
"io/fs"
"github.com/go-mizu/mizu"
"github.com/go-mizu/mizu/frontend"
)
//go:embed all:../../dist
var distFS embed.FS
func New() *mizu.App {
app := mizu.New()
// API routes
app.Get("/api/users", handleUsers)
// Embedded frontend
dist, err := fs.Sub(distFS, "dist")
if err != nil {
panic("failed to load embedded frontend: " + err.Error())
}
app.Use(frontend.WithFS(dist))
return app
}
Build Process
# 1. Build frontend
cd frontend
npm run build # Creates dist/
# 2. Build Go binary (embeds dist/)
cd ..
go build -o ./bin/server cmd/server/main.go
# 3. Deploy single binary
scp ./bin/server user@server:/app/server
Binary Size
Embedding increases binary size:
# Without embed
server: 8 MB
# With embed (typical React app)
server: 12 MB # +4 MB for frontend
# With large frontend
server: 20 MB # +12 MB
Tips to reduce size:
- Minify frontend
- Compress assets
- Remove unused code
- Use code splitting
Trade-offs
- β
Single file deployment
- β
No file serving issues
- β
Faster startup (no disk I/O)
- β
Simpler Docker images
- β
Version consistency
- β Larger binary size
- β Must rebuild for frontend changes
- β Canβt update frontend independently
- β Slower build times
When to Use
Use embedded FS when:
- Deploying to production
- Want simple deployment
- Frontend changes infrequently
- Binary size acceptable
Use file system when:
- Frequent frontend updates
- Want to update without rebuild
- Very large frontends
- Need separate frontend deployment
Hybrid Approach
Use environment variable to switch:
func getFrontendFS() fs.FS {
// Development: use file system
if os.Getenv("MIZU_ENV") != "production" {
return os.DirFS("./dist")
}
// Production: use embedded FS
dist, _ := fs.Sub(distFS, "dist")
return dist
}
app.Use(frontend.WithFS(getFrontendFS()))
Multiple Embedded Directories
Embed views and static separately:
//go:embed all:../../dist
var distFS embed.FS
//go:embed all:../../views
var viewsFS embed.FS
//go:embed all:../../static
var staticFS embed.FS
func New() *mizu.App {
app := mizu.New()
// Views
views, _ := fs.Sub(viewsFS, "views")
v := view.New(view.Config{FS: views})
app.Use(v.Middleware())
// Static assets
static, _ := fs.Sub(staticFS, "static")
app.Static("/static", static)
// Frontend SPA
dist, _ := fs.Sub(distFS, "dist")
app.Use(frontend.WithFS(dist))
return app
}
Next Steps
Building
Build process and optimization
Static Hosting
Alternative deployment options
Production
Production best practices