VoltAgent Server Architecture
VoltAgent 1.x introduces a framework-agnostic server architecture that separates core functionality from server implementation. This design allows you to use different server frameworks or create custom implementations.
Architecture Overview​
The server system consists of two main packages:
@voltagent/server-core​
The core package provides framework-agnostic components:
- Route Definitions - Standardized route specifications (
/packages/server-core/src/routes/definitions.ts) - Request Handlers - Business logic for all endpoints
- Base Provider - Abstract class for server implementations
- WebSocket Support - Real-time communication infrastructure
- Auth Interface - Pluggable authentication system
@voltagent/server-hono​
The official server implementation using Hono:
- Fast, lightweight web framework
- Built-in OpenAPI and Swagger UI support
- TypeScript-first with excellent DX
- Works with Node.js, Bun, Deno, and Edge runtimes
Core Concepts​
Server Provider Interface​
Every server implementation must satisfy the IServerProvider interface:
interface IServerProvider {
start(): Promise<{ port: number }>;
stop(): Promise<void>;
isRunning(): boolean;
}
Server Provider Factory​
Server providers are created using factory functions:
type ServerProviderFactory = (deps: ServerProviderDeps) => IServerProvider;
The ServerProviderDeps provides access to:
agentRegistry- Manage and access agentsworkflowRegistry- Manage and access workflowslogger- Logging infrastructurevoltOpsClient- Telemetry and prompt managementobservability- OpenTelemetry integration
Base Server Provider​
The BaseServerProvider class handles common server tasks:
abstract class BaseServerProvider implements IServerProvider {
// Manages port allocation
// Sets up WebSocket server
// Handles graceful shutdown
// Prints startup messages
protected abstract startServer(port: number): Promise<Server>;
protected abstract stopServer(): Promise<void>;
}
Using the Hono Server​
Basic Setup​
import { VoltAgent } from "@voltagent/core";
import { honoServer } from "@voltagent/server-hono";
new VoltAgent({
agents: { myAgent },
server: honoServer({
port: 3141,
enableSwaggerUI: true,
}),
});
Configuration Options​
interface HonoServerConfig {
// Port to listen on (default: 3141)
port?: number;
// Hostname to bind the server to (default: "0.0.0.0")
hostname?: string;
// Enable Swagger UI (default: true in dev, false in prod)
enableSwaggerUI?: boolean;
// Configure the Hono app directly
configureApp?: (app: OpenAPIHono) => void | Promise<void>;
// Authentication provider
auth?: AuthProvider;
}
Network Binding Configuration​
The hostname option controls which network interface the server binds to. This is particularly important for deployment on modern cloud platforms that use IPv6 or require dual-stack networking.
Default Behavior (IPv4)​
By default, VoltAgent binds to 0.0.0.0, which accepts connections on all IPv4 interfaces:
new VoltAgent({
agents: { myAgent },
server: honoServer({
port: 3141,
// hostname: "0.0.0.0" is the default
}),
});
IPv6 Dual-Stack (Recommended for Production)​
For platforms like Railway, Fly.io, or other IPv6-enabled environments, use :: to bind to both IPv4 and IPv6:
new VoltAgent({
agents: { myAgent },
server: honoServer({
port: 3141,
hostname: "::", // Binds to both IPv4 and IPv6
}),
});
This is the recommended configuration for production deployments as it ensures compatibility with modern networking infrastructure.
Localhost Only (Development)​
For local development when you want to restrict access to localhost only:
new VoltAgent({
agents: { myAgent },
server: honoServer({
port: 3141,
hostname: "127.0.0.1", // IPv4 localhost only
}),
});
Environment-Based Configuration​
Use environment variables for flexible deployment configuration:
new VoltAgent({
agents: { myAgent },
server: honoServer({
port: parseInt(process.env.PORT || "3141"),
hostname: process.env.HOSTNAME || "::", // Default to dual-stack
}),
});
Then set in your deployment environment:
# Railway, Fly.io, etc.
PORT=8080
HOSTNAME=::
# Local development
PORT=3141
HOSTNAME=127.0.0.1
Advanced Configuration​
Access the Hono app directly for custom middleware and routes:
new VoltAgent({
agents: { myAgent },
server: honoServer({
configureApp: (app) => {
// Add custom middleware
app.use("/admin/*", authMiddleware);
// Add custom routes
app.get("/health", (c) => c.json({ status: "ok" }));
// Create route groups
const api = app.basePath("/api/v2");
api.get("/users", getUsersHandler);
// Add rate limiting
app.use("*", rateLimiter());
},
}),
});
Port Management​
VoltAgent includes intelligent port management:
- Default Port: 3141
- Fallback Ports: If default is taken, tries 4310, 1337, etc.
- Port Allocation: Central manager prevents conflicts
- Graceful Release: Ports are released on shutdown
WebSocket Support​
WebSocket is automatically enabled for real-time features:
- Base path:
/ws - Endpoints:
/ws– connection test/echo/ws/logs– real-time logs (filterable via query params)/ws/observability– spans and logs for observability (optionalentityId/entityTypefilters)
- Protocol: Standard WebSocket with JSON messages
Note: The Hono server config does not currently expose WebSocket configuration options. WebSockets are on by default and use the /ws path. If you need to change the path or behavior, implement a custom provider using @voltagent/server-core.
Route Registration​
Routes are defined in a framework-agnostic format:
const AGENT_ROUTES = {
listAgents: {
method: "get" as const,
path: "/agents",
summary: "List all registered agents",
tags: ["Agent Management"],
responses: {
200: { description: "Success" },
500: { description: "Server error" },
},
},
// ... more routes
};
Server implementations use these definitions to:
- Generate OpenAPI documentation
- Register routes with proper handlers
- Ensure consistency across implementations
Middleware and Plugins​
The Hono server supports standard middleware. Middleware configured in configureApp runs before the default VoltAgent middleware, allowing you to override default behavior.
Middleware Execution Order​
- User's
configureApp- Your custom middleware and routes (runs first) - Default CORS - Applied only if you didn't configure custom CORS
- Authentication - If configured via
authoption - VoltAgent Routes - Built-in agent and workflow endpoints
Example: Custom Middleware​
import { cors } from "hono/cors";
import { logger } from "hono/logger";
import { compress } from "hono/compress";
configureApp: (app) => {
// Custom CORS (disables default CORS)
app.use(
"*",
cors({
origin: "https://your-domain.com",
credentials: true,
})
);
// Logging
app.use("*", logger());
// Compression
app.use("*", compress());
};
Important: If you configure CORS middleware in configureApp, the default permissive CORS (origin: "*") is automatically disabled.
Graceful Shutdown​
VoltAgent provides comprehensive shutdown handling to ensure clean resource cleanup and compatibility with other frameworks.
How Shutdown Works​
When VoltAgent receives a shutdown signal (SIGINT/SIGTERM):
- Server stops first - Prevents new requests from being accepted
- Workflows suspend - All active workflows are gracefully suspended
- Telemetry shuts down - Observability resources are properly closed
- Process exits (conditionally) - Only if VoltAgent is the sole signal handler
Automatic Shutdown Handling​
VoltAgent automatically registers SIGINT and SIGTERM handlers that clean up resources:
const voltAgent = new VoltAgent({
agents: { myAgent },
server: honoServer({ port: 3141 }),
});
// When you press Ctrl+C or the process receives SIGTERM:
// 1. Server stops accepting new connections
// 2. Active workflows are suspended
// 3. Telemetry is flushed and closed
// 4. Process exits (if no other handlers exist)
Programmatic Shutdown​
Use the shutdown() method for manual resource cleanup:
const voltAgent = new VoltAgent({
agents: { myAgent },
server: honoServer({ port: 3141 }),
});
// Later in your application
await voltAgent.shutdown();
// All resources are now cleaned up
Framework Integration​
VoltAgent respects other frameworks' shutdown handlers. When multiple handlers exist (e.g., from Adonis, NestJS, Express), VoltAgent:
- Performs its cleanup (server, workflows, telemetry)
- Does not call
process.exit() - Allows other handlers to complete their cleanup
- Lets the framework control the final exit
Example with Express:
import express from "express";
import { VoltAgent } from "@voltagent/core";
import { honoServer } from "@voltagent/server-hono";
const app = express();
const voltAgent = new VoltAgent({
agents: { myAgent },
server: honoServer({ port: 3141 }),
});
// Express graceful shutdown
process.on("SIGTERM", async () => {
console.log("Express: Closing server...");
// VoltAgent already cleaned up its resources
// Now Express can do its cleanup
server.close(() => {
console.log("Express: Server closed");
process.exit(0);
});
});
Server Provider Shutdown​
The BaseServerProvider handles common shutdown tasks:
- Closes WebSocket connections
- Stops the HTTP server
- Releases allocated ports
- Ensures all pending operations complete
Custom server providers should implement proper cleanup:
class CustomServerProvider extends BaseServerProvider {
protected async stopServer(): Promise<void> {
// Close all connections
await this.closeConnections();
// Stop the server
if (this.server) {
await new Promise((resolve) => {
this.server.close(resolve);
});
}
// Clean up any custom resources
await this.cleanupCustomResources();
}
}
Shutdown Order Matters​
Resources are cleaned up in a specific order to prevent issues:
- Server first - Stop accepting new work
- Workflows second - Suspend active operations
- Telemetry last - Ensure all events are recorded
This order ensures that:
- No new requests arrive during cleanup
- Active operations can complete or suspend gracefully
- All telemetry data is captured before shutdown
Best Practices​
- Use the Official Implementation: Start with
@voltagent/server-honounless you have specific requirements - Configure for Your Deployment: Use
hostname: "::"for production deployments to support both IPv4 and IPv6 - Leverage configureApp: Add custom routes and middleware through the configuration
- Follow Route Definitions: Use the standardized route definitions for consistency
- Handle Errors Properly: Implement proper error handling in custom providers
- Support Graceful Shutdown: Always clean up resources properly
- Test Shutdown Behavior: Verify your application exits cleanly in different scenarios
- Use
shutdown()in Tests: Ensure proper cleanup in test suites - Environment Variables: Use environment variables for port and hostname configuration to support different deployment environments
Next Steps​
- Learn about Authentication to secure your API
- Explore Custom Endpoints to extend the API
- Check Agent Endpoints for API usage