Vyuh Server
A pure-Dart server framework with Vyuh-style plugin and feature ergonomics. Build complex backend services by composing plugins (storage, auth, telemetry, query, policy) and features (domain routes) — both speaking the same five-slot contribution language.
Why Vyuh Server?
Plugins & Features in One Mental Model
Both contribute through the same five slots — routes, middlewares, per-request context, DI bindings, and descriptors — plus an imperative escape hatch. Learn one, you know the other.
Pluggable Storage, Auth, Telemetry, Filters, Policy
Typed plugin contracts for every cross-cutting concern. Swap Postgres for SQLite, JWT for API key, console logs for OpenTelemetry — nothing else changes.
Declarative Descriptors
Features describe capabilities as data — EntityCrudDescriptor<T>, ErrorCodesDescriptor — and the matching plugin claims the type at boot. Unhandled descriptors fail fast at startup.
Built on Relic
Production-grade HTTP transport with onion middleware, request-scoped DI, graceful shutdown on SIGINT/SIGTERM, and a self-advertising banner that lists every URL each plugin owns.
Getting Started
Core Concepts
Key Components
| Component | Description |
|---|---|
| VyuhServer | The runtime returned by bootstrap. Holds resolved plugin singletons, features, DI container, and env registry |
| Plugin | Cross-cutting infrastructure contributor. Subtypes: DbPlugin, AuthPlugin, TelemetryPlugin, QueryPlugin, PolicyPlugin, EnvPlugin |
| FeatureDescriptor | Domain-area contributor. Same five contribution slots as Plugin (routes, middlewares, context, di, descriptors) |
| RouteSpec / MiddlewareSpec | Declarative wire shapes for mounting handlers and onion middleware with explicit ordering |
| RouteModule | Named, basePath-scoped grouping of routes with co-located auth requirements |
| Descriptor / DescriptorHandler<D> | Open extension mechanism. Features describe capabilities as data; plugins claim the type |
| vyuh global accessor | Route-side accessor exposing storage, auth, telemetry, filter, policy, di, env, and errors |
| DbAdapter | Relational-OLTP boundary: transactions, DDL, parameterized SQL, pub/sub LISTEN/NOTIFY |
Learn More
The Five-Slot Contribution Model
Every plugin AND every feature contributes through the same five primitives, plus an imperative escape hatch. Anyone fluent in one is fluent in the other:
| Slot | Type | Purpose |
|---|---|---|
routes | List<RouteSpec> | Method + path + handler tuples |
middlewares | List<MiddlewareSpec> | Path-scoped middleware in onion order |
context | List<ContextProvider> | Per-request typed value providers |
di | List<DiRegistration> | Server-wide DI bindings on vyuh.di |
descriptors | List<Descriptor> | Open extension — claimed by a Plugin<D> |
extend | (scope) => … | Imperative escape hatch over the live RouterScope |
The distinction between Plugin and Feature is identity, not capability:
- Plugin — a singleton role for the server (one storage, one auth, one OpenAPI). Publishes typed verbs on
vyuh.X. - Feature — a composable domain area (catalog, billing, reports). Many per server.
Quick Example
Bootstrap a SaaS API with Postgres, JWT auth, OpenTelemetry tracing, and an auto-generated OpenAPI explorer at /docs:
import 'package:vyuh_server/vyuh_server.dart';
import 'package:vyuh_server_plugin_postgres/vyuh_server_plugin_postgres.dart';
import 'package:vyuh_server_plugin_auth_jwt/vyuh_server_plugin_auth_jwt.dart';
import 'package:vyuh_server_plugin_telemetry_otel/vyuh_server_plugin_telemetry_otel.dart';
import 'package:vyuh_server_plugin_openapi/vyuh_server_plugin_openapi.dart';
import 'package:cdx_query_server_postgres/cdx_query_server_postgres.dart';
import 'package:vyuh_server_plugin_entity_crud/vyuh_server_plugin_entity_crud.dart';
Future<void> main() async {
final runtime = await VyuhServer.bootstrap(
name: 'saas-api',
plugins: [
EnvPlugin(
configs: [TypedEnvConfig.factory(PostgresConnectionConfig.new)],
),
PostgresDbPlugin(),
JwtAuthPlugin(verifier: verifyTokenWithJwks),
OtelTelemetryPlugin(defaultServiceName: 'saas-api'),
PostgresQueryPlugin(),
EntityCrudPlugin(),
OpenApiPlugin(
title: 'SaaS API',
version: '2.4.0',
description: 'Multi-tenant SaaS backend',
),
],
features: [
catalogFeature,
billingFeature,
reportsFeature,
],
);
await runtime.start(
port: 8080,
middleware: [
GlobalMiddleware.cors(),
GlobalMiddleware.errorHandler(),
GlobalMiddleware.requestLogger(),
GlobalMiddleware.auth(),
],
);
}That's a fully wired production server. The startup banner prints:
saas-api listening on http://localhost:8080
Docs: http://localhost:8080/docs
Spec: http://localhost:8080/openapi.jsonSee the Quick Start for a step-by-step build, or the SaaS API example for the full feature breakdown.