English | 中文
Build serverless, reliable apps at lightspeed ⚡ — with confidence 🛡️.
Anclax is a definition‑first framework for small–medium apps (single PostgreSQL). Define APIs and tasks as schemas; generated code moves correctness to compile time.
Join our Discord server.
Use the Anclax skill with the coding agent:
- Install Anclax CLI:
go install github.com/cloudcarver/anclax/cmd/anclax@latest- Init your project:
anclax init myapp github.com/me/myapp
cd myapp- Add Anclax skill to your coding agent
npx skills add cloudcarver/anclax- YAML-first, codegen-backed: Define HTTP and task schemas in YAML; Anclax generates strongly-typed interfaces so missing implementations fail at compile time, not in prod.
- Async tasks you can trust: At-least-once delivery, automatic retries, and cron scheduling out of the box.
- Transaction-safe flows: A
WithTxpattern ensures hooks always run and side effects are consistent. - Typed database layer: Powered by
sqlcfor safe, fast queries. - Fast HTTP server: Built on Fiber for performance and ergonomics.
- AuthN/Z built-in: Macaroons-based authentication and authorization.
- Pluggable architecture: First-class plugin system for clean modularity.
- Ergonomic DI: Wire-based dependency injection keeps code testable and explicit.
- Glue-code fatigue: Many teams stitch HTTP, DB, tasks, DI, and auth by hand, leaving implicit contracts and runtime surprises. Anclax makes those contracts explicit and generated.
- Background jobs are hard: Idempotency, retries, and delivery guarantees are non-trivial. Anclax ships a task engine with at-least-once semantics and cron.
- Consistency across boundaries: Keep handlers, tasks, and hooks transactional using
WithTxso invariants hold. - Confidence and testability: Every generated interface is mockable; behavior is easy to test.
- Compile-time confidence: Schema → interfaces → concrete implementations you cannot forget to write.
- Productivity:
anclax init+anclax genreduces boilerplate and wiring. - Extensibility: Clean plugin boundaries and event-driven architecture.
- Predictability: Singletons for core services, DI for clarity, and well-defined lifecycles.
Anclax helps you build quickly while staying scalable and production‑ready.
- Single PostgreSQL backbone: One PostgreSQL database powers both transactional business logic and the durable task queue, keeping state consistent and operations simple. For many products, a well‑provisioned instance (e.g., 32 vCPU) goes a very long way.
- Stateless application nodes: HTTP servers are stateless and horizontally scalable; you can run multiple replicas without coordination concerns.
- Task queue as integration fabric: Use async tasks to decouple modules. For example, when a payment completes, enqueue an
OrderFinishedtask and do any factory‑module inserts in its handler—no factory logic inside the payment module. - Built‑in worker, flexible deployment: Anclax includes an async task worker. Run it in‑process, as separate long‑running workers, or disable it for serverless HTTP (e.g., AWS Lambda) while keeping workers on regular servers.
- Monolith, not microservices: Anclax favors a pragmatic, scalable monolith and is not aimed at multi‑million QPS microservice fleets.
These choices maximize early velocity and give you a clear, reliable path to scale with confidence.
# 1) Scaffold into folder 'demo'
anclax init demo github.com/you/demo
# 2) Generate code (can be re-run anytime)
cd demo
anclax gen
# 3) Start the stack (DB + API + worker)
docker compose upIn another terminal:
curl http://localhost:2910/api/v1/counter
# Optional sign-in if your template includes auth
curl -X POST http://localhost:2910/api/v1/auth/sign-in -H "Content-Type: application/json" -d '{"name":"test","password":"test"}'- Define an endpoint (OpenAPI YAML) 🧩
paths:
/api/v1/counter:
get:
operationId: getCounter- Define a task ⏱️
tasks:
incrementCounter:
description: Increment the counter value
cron: "*/1 * * * *"- Generate and implement 🛠️
anclax genfunc (h *Handler) GetCounter(c *fiber.Ctx) error {
return c.JSON(apigen.Counter{Count: 0})
}x-check-rules:
OperationPermit:
useContext: true
parameters:
- name: operationID
schema:
type: string
ValidateOrgAccess:
useContext: true
parameters:
- name: orgID
schema:
type: integer
format: int32
paths:
/orgs/{orgID}/projects/{projectID}:
get:
operationId: GetProject
security:
- BearerAuth:
- x.ValidateOrgAccess(c, orgID, "viewer")
- x.OperationPermit(c, operationID)components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: macaroon- Pain points before: hand-building
apigen.Taskpayloads and attributes was repetitive and easy to get wrong. - Pain points before: retry/cron/unique-tag logic got duplicated and drifted across services.
- Pain points before: enqueueing inside a DB transaction required custom glue code.
- Pain points before: task params and handler signatures could fall out of sync.
Refactor solution: define tasks in api/tasks.yaml, run anclax gen, and use the generated taskgen.TaskRunner (RunX / RunXWithTx) with taskcore overrides when needed.
# api/tasks.yaml
tasks:
- name: SendWelcomeEmail
description: Send welcome email to new users
parameters:
type: object
required: [userId, templateId]
properties:
userId:
type: integer
format: int32
templateId:
type: string
retryPolicy:
interval: 5m
maxAttempts: 3
cron: "0 * * * *"Before (manual task record):
params := &taskgen.SendWelcomeEmailParameters{UserId: user.ID, TemplateId: "welcome"}
payload, err := params.Marshal()
if err != nil {
return err
}
task := &apigen.Task{
Spec: apigen.TaskSpec{Type: taskgen.SendWelcomeEmail, Payload: payload},
Attributes: apigen.TaskAttributes{
RetryPolicy: &apigen.TaskRetryPolicy{Interval: "5m", MaxAttempts: 3},
},
Status: apigen.Pending,
}
taskID, err := taskStore.PushTask(ctx, task)After (generated runner + transaction-safe enqueue):
err := model.RunTransactionWithTx(ctx, func(tx core.Tx, txm model.ModelInterface) error {
_, err := taskrunner.RunSendWelcomeEmailWithTx(ctx, tx, &taskgen.SendWelcomeEmailParameters{
UserId: user.ID,
TemplateId: "welcome",
}, taskcore.WithUniqueTag("welcome:"+strconv.Itoa(int(user.ID))))
return err
})func (s *Service) CreateUserWithTx(ctx context.Context, tx pgx.Tx, username, password string) (int32, error) {
txm := s.model.SpawnWithTx(tx)
userID, err := txm.CreateUser(ctx, username, password)
if err != nil { return 0, err }
if err := s.hooks.OnUserCreated(ctx, tx, userID); err != nil { return 0, err }
_, err = s.taskRunner.RunSendWelcomeEmailWithTx(ctx, tx, &taskgen.SendWelcomeEmailParameters{ UserId: userID })
return userID, err
}func NewGreeter(m model.ModelInterface) (*Greeter, error) { return &Greeter{Model: m}, nil }func InitApp() (*app.App, error) {
wire.Build(model.NewModel, NewGreeter /* ...other providers... */)
return nil, nil
}-- name: GetCounter :one
SELECT value FROM counter LIMIT 1;
-- name: IncrementCounter :exec
UPDATE counter SET value = value + 1;You can run custom logic before the app starts by providing an Init function:
// Runs before the application starts
func Init(anclaxApp *anclax_app.Application, taskrunner taskgen.TaskRunner, myapp anclax_app.Plugin) (*app.App, error) {
if err := anclaxApp.Plug(myapp); err != nil {
return nil, err
}
if _, err := anclaxApp.GetService().CreateNewUser(context.Background(), "test", "test"); err != nil {
return nil, err
}
if _, err := taskrunner.RunAutoIncrementCounter(context.Background(), &taskgen.AutoIncrementCounterParameters{
Amount: 1,
}, taskcore.WithUniqueTag("auto-increment-counter")); err != nil {
return nil, err
}
return &app.App{ AnclaxApp: anclaxApp }, nil
}To customize how the Anclax application is constructed, override InitAnclaxApplication:
func InitAnclaxApplication(cfg *config.Config) (*anclax_app.Application, error) {
anclaxApp, err := anclax_wire.InitializeApplication(&cfg.Anclax, anclax_config.DefaultLibConfig())
if err != nil {
return nil, err
}
return anclaxApp, nil
}Need more dependencies inside Init? Add them as parameters (e.g., model.ModelInterface) and run anclax gen.
- Transaction Management: docs/transaction.md (中文)
- Middleware (x-functions & x-check-rules): docs/middleware.md (中文)
- Async Tasks: Tutorial docs/async-tasks-tutorial.md · Tech reference docs/async-tasks-technical.md (中文, 中文)
examples/simple— minimal end-to-end sample with HTTP, tasks, DI, and DB.
