> ## 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.

# Production

> Deploy your views in production with embedded templates and caching

This guide covers everything you need to deploy your Mizu views in production: embedding templates, caching, performance optimization, and best practices.

## Embedding Templates

In production, embed templates into your binary. This eliminates file system dependencies and ensures templates can't be accidentally modified.

### Using embed.FS

Go's `embed` package lets you include files in your binary:

```go theme={null}
package main

import (
    "embed"

    "github.com/go-mizu/mizu"
    "github.com/go-mizu/mizu/view"
)

//go:embed views
var viewsFS embed.FS

func main() {
    engine := view.New(view.Config{
        FS:            viewsFS,    // Use embedded filesystem
        Extension:     ".html",
        DefaultLayout: "default",
    })

    app := mizu.New()
    app.Use(engine.Middleware())

    // ... routes ...

    app.Listen(":8080")
}
```

### Directory Structure for Embedding

The `//go:embed` directive embeds a directory relative to the source file:

```
myapp/
├── main.go           # Contains //go:embed views
├── views/
│   ├── layouts/
│   │   └── default.html
│   └── pages/
│       ├── home.html
│       └── about.html
└── go.mod
```

After building, the binary contains all templates.

### Conditional Embedding

Use environment variables to switch between development and production:

```go theme={null}
package main

import (
    "embed"
    "os"

    "github.com/go-mizu/mizu"
    "github.com/go-mizu/mizu/view"
)

//go:embed views
var viewsFS embed.FS

func main() {
    isDev := os.Getenv("ENV") != "production"

    config := view.Config{
        Extension:     ".html",
        DefaultLayout: "default",
        Development:   isDev,
    }

    if isDev {
        // Development: filesystem for hot reload
        config.Dir = "./views"
    } else {
        // Production: embedded with caching
        config.FS = viewsFS
    }

    engine := view.New(config)

    // ... rest of application
}
```

## Preloading Templates

In production, preload all templates at startup to:

1. **Fail fast** - Catch template errors before serving requests
2. **Warm cache** - Avoid first-request latency
3. **Validate** - Ensure all templates parse correctly

```go theme={null}
engine := view.New(view.Config{
    FS:            viewsFS,
    DefaultLayout: "default",
})

// Preload and validate all templates
if err := engine.Load(); err != nil {
    log.Fatal("Template error:", err)
}

app := mizu.New()
app.Use(engine.Middleware())
```

### Preload Errors

`Load()` catches errors like:

* Missing template files
* Template syntax errors
* Invalid template references

```go theme={null}
err := engine.Load()
if err != nil {
    // err contains details about the failure
    log.Fatal(err)
}
```

## Performance Optimization

### Template Caching

In production mode (`Development: false`), templates are cached:

* **Parsed once** - Templates are parsed at first use or Load()
* **Reused** - Same parsed template serves all requests
* **No disk I/O** - Templates read from memory

```go theme={null}
view.Config{
    Development: false,  // Enable caching (default)
}
```

### Pre-compute in Handlers

Move complex logic to Go:

```go theme={null}
// Good: compute once in handler
func handler(c *mizu.Ctx) error {
    posts := fetchPosts()

    // Pre-compute derived data
    featured := filterFeatured(posts)
    byCategory := groupByCategory(posts)

    return view.Render(c, "posts", view.Data{
        "Posts":      posts,
        "Featured":   featured,
        "ByCategory": byCategory,
    })
}
```

```html theme={null}
<!-- Simple template: just displays pre-computed data -->
{{range .Data.Featured}}
    <article>{{.Title}}</article>
{{end}}
```

### Minimize Template Complexity

Complex templates are slower. Keep them focused:

```html theme={null}
<!-- Avoid: deeply nested conditionals -->
{{if .Data.A}}
    {{if .Data.B}}
        {{if .Data.C}}
            ...
        {{end}}
    {{end}}
{{end}}

<!-- Better: compute in Go, pass simple flag -->
{{if .Data.ShowSpecialContent}}
    ...
{{end}}
```

## Error Handling

### Custom Error Pages

Create error page templates:

```html theme={null}
<!-- views/pages/404.html -->
<div class="error-page">
    <h1>404</h1>
    <p>The page you're looking for doesn't exist.</p>
    <a href="/">Go Home</a>
</div>
```

```html theme={null}
<!-- views/pages/500.html -->
<div class="error-page">
    <h1>500</h1>
    <p>Something went wrong on our end.</p>
    <p>Please try again later.</p>
</div>
```

### Error Handler

Set up a global error handler:

```go theme={null}
app := mizu.New()

app.ErrorHandler = func(c *mizu.Ctx, err error) {
    code := 500
    page := "500"

    // Check for HTTP errors
    var httpErr *mizu.Error
    if errors.As(err, &httpErr) {
        code = httpErr.Code
        if code == 404 {
            page = "404"
        }
    }

    // Log server errors
    if code >= 500 {
        log.Printf("Server error: %v", err)
    }

    // Render error page
    c.Status(code)
    if renderErr := view.Render(c, page, view.Data{
        "Title": "Error",
        "Error": err,
    }); renderErr != nil {
        // Fallback if error page fails
        c.Text("An error occurred")
    }
}
```

### Template Error Handling

Handle template rendering errors gracefully:

```go theme={null}
func handler(c *mizu.Ctx) error {
    err := view.Render(c, "page", data)
    if err != nil {
        // Log the error
        log.Printf("Template error: %v", err)

        // Return generic error
        return c.Status(500).Text("Internal error")
    }
    return nil
}
```

## Security

### Content Security Policy

Set appropriate headers:

```go theme={null}
app.Use(func(next mizu.Handler) mizu.Handler {
    return func(c *mizu.Ctx) error {
        c.Set("Content-Security-Policy",
            "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'")
        return next(c)
    }
})
```

### HTML Escaping

Go templates escape HTML by default. Only bypass escaping for trusted content:

```html theme={null}
<!-- Safe: auto-escaped -->
{{.Data.UserComment}}

<!-- Only for trusted content -->
{{.Data.TrustedHTML}}
```

```go theme={null}
import "html/template"

view.Data{
    "TrustedHTML": template.HTML(trustedContent),
}
```

### CSRF Tokens

Include CSRF tokens in forms:

```html theme={null}
<form method="POST" action="/submit">
    <input type="hidden" name="csrf_token" value="{{.Data.CSRFToken}}">
    <!-- form fields -->
</form>
```

## Monitoring

### Template Metrics

Track template rendering performance:

```go theme={null}
func handler(c *mizu.Ctx) error {
    start := time.Now()

    err := view.Render(c, "page", data)

    duration := time.Since(start)
    metrics.RecordTemplateRender("page", duration)

    return err
}
```

### Health Checks

Verify templates work in health checks:

```go theme={null}
app.Get("/health", func(c *mizu.Ctx) error {
    // Try rendering a simple template
    engine := view.From(c)
    var buf bytes.Buffer
    err := engine.Render(&buf, "health-check", nil, view.NoLayout())
    if err != nil {
        return c.Status(500).JSON(map[string]string{
            "status": "unhealthy",
            "error":  err.Error(),
        })
    }

    return c.JSON(map[string]string{
        "status": "healthy",
    })
})
```

## Deployment Checklist

### Before Deploying

* [ ] Set `Development: false`
* [ ] Use `embed.FS` for templates
* [ ] Call `Load()` at startup
* [ ] Create error page templates
* [ ] Set up error handler
* [ ] Test all pages render correctly

### Environment Variables

```bash theme={null}
# Production
ENV=production
PORT=8080

# Development
ENV=development
PORT=8080
```

### Docker Example

```dockerfile theme={null}
FROM golang:1.22-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 go build -o server .

FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/server .

# Templates are embedded - no need to copy views/

ENV ENV=production
EXPOSE 8080
CMD ["./server"]
```

## Complete Production Setup

```go theme={null}
package main

import (
    "embed"
    "errors"
    "log"
    "os"

    "github.com/go-mizu/mizu"
    "github.com/go-mizu/mizu/view"
)

//go:embed views
var viewsFS embed.FS

func main() {
    // Configuration
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    isDev := os.Getenv("ENV") != "production"

    // Create view engine
    config := view.Config{
        Extension:     ".html",
        DefaultLayout: "default",
        Development:   isDev,
    }

    if isDev {
        config.Dir = "./views"
    } else {
        config.FS = viewsFS
    }

    engine := view.New(config)

    // Preload in production
    if !isDev {
        if err := engine.Load(); err != nil {
            log.Fatal("Template error:", err)
        }
        log.Println("Templates loaded successfully")
    }

    // Create app
    app := mizu.New()
    app.Use(engine.Middleware())

    // Error handler
    app.ErrorHandler = func(c *mizu.Ctx, err error) {
        code := 500
        page := "500"

        var httpErr *mizu.Error
        if errors.As(err, &httpErr) {
            code = httpErr.Code
            if code == 404 {
                page = "404"
            }
        }

        if code >= 500 {
            log.Printf("Error: %v", err)
        }

        c.Status(code)
        view.Render(c, page, view.Data{"Title": "Error"})
    }

    // Routes
    app.Get("/", homeHandler)
    app.Get("/about", aboutHandler)

    // Start server
    log.Printf("Server starting on :%s (dev=%v)", port, isDev)
    if err := app.Listen(":" + port); err != nil {
        log.Fatal(err)
    }
}

func homeHandler(c *mizu.Ctx) error {
    return view.Render(c, "home", view.Data{
        "Title": "Welcome",
    })
}

func aboutHandler(c *mizu.Ctx) error {
    return view.Render(c, "about", view.Data{
        "Title": "About Us",
    })
}
```

## What's Next?

Now that your views are ready for production, explore:

* **[Sync Overview](/view/sync-overview)** - Client-side state synchronization
* **[Live Overview](/view/live-overview)** - Real-time WebSocket communication
