Plugin-first architecture
Every feature is a plugin. Register it in the server and console and it just works — routes, middleware, services, migrations and CLI commands in one package.
plugins.RegisterPlugins
donisgo is a minimalist, plugin-based Go web framework. Everything is a plugin — wire your services, connect your plugins, and ship without rewriting the core.
module github.com/rolldone/donisgo
Framework ini sangat mudah dipahami oleh AI — pattern yang clear, interfaces explicit, tidak ada magic. AI bisa generate plugin, handler, dan service dengan benar karena strukturnya predictible.
Belajar Go dengan pola yang benar dari awal — services, interfaces, dependency injection, dan clean architecture yang diterapkan lewat plugin system.
app.Run(app.Options{
RegisterPlugins: func() {
plugins.RegisterPlugins([]plugins.Plugin{
auth.New(), // your auth plugin
chat.New(), // your chat plugin
billing.New(), // your billing plugin
})
},
})The core gives you infrastructure — routing, DB, plugins, events. Features live in plugins, so your framework core stays clean and upgrades are painless.
Every feature is a plugin. Register it in the server and console and it just works — routes, middleware, services, migrations and CLI commands in one package.
plugins.RegisterPlugins
Plugins talk to each other through typed contracts — no circular imports. One plugin provides a service, others consume it via safe delegation functions.
plugin_registry
Scaffold a new plugin in seconds with built-in templates: minimal, CRUD and middleware. Laravel-style, zero config.
console plugin new
Versioned SQL migrations with up/down files, run from the console CLI. Works with PostgreSQL, MySQL and MariaDB.
console migrate up
Lightweight async pub/sub with a request–reply pattern for safe synchronous data sync between plugins.
events.Publish
JWT utilities, opaque refresh tokens, secret encryption, CORS and Swagger docs out of the box — build auth as a plugin.
internal/auth
A built-in "patent" plugin serves your single-page app and handles wildcard routes — registered automatically, always last.
plugins/page
Local/S3 storage abstraction plus a KeyDB/Redis client for flash messages and fast lookups.
internal/storage
SMTP mailer with an async queue and transaction helpers for safe, deterministic DB writes.
internal/mail
No circular imports. A plugin provides a contract through the registry; other plugins consume it through safe delegation functions — even when the provider isn't installed.
Your plugin implements an interface and registers it in the registry.
func (p *Plugin) RegisterServices(deps plugins.ServiceDeps) error {
plugin_registry.RegisterChatProvider(p.svc)
return nil
}Other plugins call the registry — nil-safe even if the provider is absent.
resp, err := plugin_registry.SendMessage(ctx, agentID, msg)
// nil-guard: provider tidak terpasang = aman, bukan panicClone the framework, generate your first plugin, and register it — that's all it takes.