Skip to content

Addons

Addons are separate Go modules that implement ss-keel-core/contracts.

This is the extension model used across the Keel ecosystem:

  • ss-keel-core owns the runtime and the contracts package
  • addon repositories implement those contracts
  • applications decide which addons to compose in main.go

See Architecture for the layer boundaries.

The persistence layer is not built into core. It lives in official addons.

PackageDescriptionContract
ss-keel-gormOfficial relational persistence addon for PostgreSQL, MySQL, MariaDB, SQLite, and SQL Servercontracts.Repository[T, ID, httpx.PageQuery, httpx.Page[T]]
ss-keel-mongoOfficial MongoDB persistence addon using the official Go drivercontracts.Repository[T, ID, httpx.PageQuery, httpx.Page[T]]

Official example coverage today:

  • ss-keel-examples/examples/08-gorm-postgres for ss-keel-gorm
  • ss-keel-examples/examples/13-mongo for ss-keel-mongo
  • ss-keel-examples/examples/14-redis-cache for ss-keel-redis
  • ss-keel-examples/examples/10-addon-example for addon consumption patterns

See Persistence for the official persistence overview.

The addon ecosystem is organized into three repositories:

  • keel: provides keel add and executes addon installation steps
  • ss-keel-addon-template: GitHub template to bootstrap new addon repositories
  • ss-keel-addons: official alias registry consumed by keel add

Recommended entry points:

PackageDescriptionContract
ss-keel-gormRelational persistence via GORMRepository[T, ID, httpx.PageQuery, httpx.Page[T]]
ss-keel-mongoMongoDB persistence via mongo-driverRepository[T, ID, httpx.PageQuery, httpx.Page[T]]
PackageDescriptionContract
ss-keel-redisRedis via go-redis for cache and sessionsCache
PackageDescriptionContract
ss-keel-jwtJWT generation, validation, and guardsGuard
ss-keel-oauthOAuth2 providers and guardsGuard

Each addon is a contract implementation. You can build one without changing the runtime:

type InMemoryCache struct {
mu sync.RWMutex
store map[string][]byte
}
func (c *InMemoryCache) Get(ctx context.Context, key string) ([]byte, error) {
c.mu.RLock()
defer c.mu.RUnlock()
v, ok := c.store[key]
if !ok {
return nil, errors.New("key not found")
}
return v, nil
}

See Contracts for the full contract catalog.