Plugin Development Overview 
Extend Nylon with custom logic running in the same process. Plugins can participate in every phase of the request lifecycle (request, response headers, response body, logging) and can also handle WebSocket connections.
At a glance
- Build shared libraries (.so) via the Go SDK (more languages on the roadmap).
- Register phase handlers to run code before/after routing, modify responses, or stream bodies.
- Leverage middleware payloads to pass configuration from YAML to your plugin.
- Use helper APIs to read/modify requests, responses, and WebSocket streams.
Plugin Architecture 
Plugins are shared libraries (.so files) that implement the Nylon plugin interface. They run in the same process as Nylon for maximum performance using Foreign Function Interface (FFI).
┌─────────────────────────────────┐
│         Nylon Core              │
│                                 │
│  ┌───────────────────────────┐  │
│  │     Request Flow          │  │
│  │                           │  │
│  │  1. RequestFilter         │  │◄── Plugin intercepts here
│  │  2. Route Matching        │  │
│  │  3. Backend Selection     │  │
│  │  4. ResponseFilter        │  │◄── Plugin intercepts here
│  │  5. ResponseBodyFilter    │  │◄── Plugin intercepts here
│  │  6. Logging               │  │◄── Plugin intercepts here
│  │                           │  │
│  └───────────────────────────┘  │
└─────────────────────────────────┘Plugin Phases 
Plugins can hook into different phases of request processing:
1. RequestFilter 
Execute before the request is sent to the backend:
- Authentication and authorization
- Request validation
- Header manipulation
- Rate limiting
- Request transformation
2. ResponseFilter 
Execute after receiving response headers from backend:
- Response header modification
- Status code changes
- Redirect logic
- Caching decisions
3. ResponseBodyFilter 
Execute while streaming response body:
- Content transformation
- Compression
- Filtering
- Body modification
4. Logging 
Execute after the request is complete:
- Access logging
- Metrics collection
- Analytics
- Error tracking
Quick start plugin 
package main
import "C"
import sdk "github.com/AssetsArt/nylon/sdk/go/sdk"
func main() {}
func init() {
	plugin := sdk.NewNylonPlugin()
	
	// Register phase handlers
	plugin.AddPhaseHandler("my-handler", func(phase *sdk.PhaseHandler) {
		// RequestFilter phase
		phase.RequestFilter(func(ctx *sdk.PhaseRequestFilter) {
			// Your logic here
			ctx.Next() // Continue to next phase
		})
		
		// ResponseFilter phase
		phase.ResponseFilter(func(ctx *sdk.PhaseResponseFilter) {
			// Your logic here
			ctx.Next()
		})
		
		// ResponseBodyFilter phase
		phase.ResponseBodyFilter(func(ctx *sdk.PhaseResponseBodyFilter) {
			// Your logic here
			ctx.Next()
		})
		
		// Logging phase
		phase.Logging(func(ctx *sdk.PhaseLogging) {
			// Your logic here
			ctx.Next()
		})
	})
}Request & response access 
The SDK exposes ergonomic helpers to inspect the inbound request and craft responses without juggling raw pointers.
Reading request data 
phase.RequestFilter(func(ctx *sdk.PhaseRequestFilter) {
	req := ctx.Request()
	
	// URL and path
	url := req.URL()           // Full URL
	path := req.Path()         // Path only
	query := req.Query()       // Query string
	
	// Headers
	auth := req.Header("Authorization")
		headers := req.Headers().GetAll()
	
	// Method and metadata
	method := req.Method()     // GET, POST, etc.
	host := req.Host()         // Host header
	clientIP := req.ClientIP() // Client IP address
	
	// Route parameters
	params := req.Params()     // URL parameters
	userId := params["user_id"]
	
	// Body
	body := req.RawBody()      // Read request body (byte slice)
	
	// Timestamp
	timestamp := req.Timestamp() // Request timestamp (ms)
	
	ctx.Next()
})Modifying responses 
phase.ResponseFilter(func(ctx *sdk.PhaseResponseFilter) {
	res := ctx.Response()
	
	// Set status
	res.SetStatus(200)
	
	// Set headers
	res.SetHeader("X-Custom-Header", "value")
	res.SetHeader("Cache-Control", "no-cache")
	res.RemoveHeader("Server")
	
	// Set body
	res.BodyRaw([]byte("Hello, World!"))
	res.BodyText("Hello, World!")
	
	ctx.Next()
})Access logging example 
phase.Logging(func(ctx *sdk.PhaseLogging) {
	req := ctx.Request()
	res := ctx.Response()
	
	log.Printf(
		"%s %s | Status: %d | ReqBytes: %d | ResBytes: %d | Duration: %dms | Client: %s",
		req.Method(),
		req.Path(),
		res.Status(),
		req.Bytes(),
		res.Bytes(),
		res.Duration(),
		req.ClientIP(),
	)
	
	// Log errors if any
	if err := res.Error(); err != "" {
		log.Printf("Error: %s", err)
	}
	
	ctx.Next()
})Building Plugins 
1. Create Plugin File 
// plugin.go
package main
import "C"
import sdk "github.com/AssetsArt/nylon/sdk/go/sdk"
func main() {}
func init() {
	plugin := sdk.NewNylonPlugin()
}2. Build as Shared Library 
go build -buildmode=c-shared -o myplugin.so3. Configure in Nylon 
plugins:
  - name: myplugin
    type: ffi
    file: ./myplugin.so
    config:
      some_flag: true
services:
  - name: backend
    service_type: http
    endpoints:
      - ip: 127.0.0.1
        port: 3000
routes:
  - route:
      type: host
      value: example.com
    name: main
    paths:
      - path:
          - /
          - /{*path}
        service:
          name: backend
        middleware:
          - plugin: myplugin
            entry: "my-handler"Tip: The
entryvalue must match the name you pass toAddPhaseHandlerin your plugin (e.g."my-handler"in the example above).
You can optionally provide structured data to the handler via payload:
middleware:
  - plugin: myplugin
    entry: "my-handler"
    payload:
      api_key: "secret"
      mode: "strict"Best Practices 
1. Always Call ctx.Next() 
Unless you want to stop the request flow:
phase.RequestFilter(func(ctx *sdk.PhaseRequestFilter) {
	// Do your work
	
	// Continue processing
	ctx.Next()
})2. Handle Errors Gracefully 
phase.RequestFilter(func(ctx *sdk.PhaseRequestFilter) {
	req := ctx.Request()
	body := req.RawBody()
	
	var data map[string]interface{}
	if err := json.Unmarshal(body, &data); err != nil {
		res := ctx.Response()
		res.SetStatus(400)
		res.BodyText("Invalid JSON")
		res.RemoveHeader("Content-Length")
		res.SetHeader("Transfer-Encoding", "chunked")
		ctx.End()
		return
	}
	
	ctx.Next()
})3. Minimize Allocations 
// Good: Reuse buffers
var bufPool = sync.Pool{
	New: func() interface{} {
		return new(bytes.Buffer)
	},
}
phase.ResponseBodyFilter(func(ctx *sdk.PhaseResponseBodyFilter) {
	buf := bufPool.Get().(*bytes.Buffer)
	defer bufPool.Put(buf)
	buf.Reset()
	
	// Use buffer
	
	ctx.Next()
})4. Use Context for State 
phase.RequestFilter(func(ctx *sdk.PhaseRequestFilter) {
	// Access middleware payload provided in YAML config
	payload := ctx.GetPayload()
	if apiKey, ok := payload["api_key"].(string); ok {
		req := ctx.Request()
		if req.Header("X-API-Key") != apiKey {
			res := ctx.Response()
			res.SetStatus(401)
			res.BodyText("Unauthorized")
			ctx.End()
			return
		}
	}
	ctx.Next()
})Next Steps 
- Learn about Plugin Phases in detail
- Explore the Go SDK API
- See Plugin Examples
- Reuse configuration patterns from core middleware