Skip to main content
SaaSFormation
Docs
EN
OO · DDD · CQRS · Event Sourcing

The TypeScript framework for
enterprise SaaS

Object-oriented and domain-driven by design. Built for teams shipping complex, multi-tenant SaaS on microservices — not just landing pages.

$ sf init
 Monorepo created

$ sf generate microservice crm
 crm microservice created

$ sf run
 crm microservice started  → http://localhost:3000/
 admin panel companion started  → http://localhost:3001/

Built for real complexity

Most frameworks stop at routing and auth. SaaSFormation goes further.

Event Sourcing first-class

Aggregate roots, domain events, and projections with built-in replay. Your event log is the source of truth.

Type-safe inter-service communication

Shared TypeScript contracts across service boundaries. No runtime surprises when services talk to each other.

Unified Message Bus

HTTP requests, commands, queries, and domain events all follow the message bus pattern. Every bus accepts middleware — add logging, auth, or tracing once and it applies everywhere.

DDD + DI out of the box

Reflect-metadata DI container with constructor injection. Repositories, services, and handlers wire themselves.

Observability ready

OpenTelemetry traces and Grafana dashboards pre-configured. Know exactly what your services are doing in production.

HTTP + JSON:API

Standards-compliant JSON:API with built-in Swagger documentation. Versioned, consistent endpoints your consumers can explore and test from day one.

The way handlers should look

No spaghetti. Clean, typed, testable command handlers with the dependencies they need — and nothing else.

  • Constructor injection via @Inject — no service locators
  • Domain events dispatched automatically by the repository on save
  • Fully typed — CommandHandler<T> enforces the contract
import { Inject } from "@saasformation/di";
import { CommandHandler } from "@saasformation/message-bus";

@CommandHandler(RegisterUser)
export class RegisterUserHandler
  implements CommandHandler<RegisterUser>
{
  constructor(
    @Inject(UserRepository)
    private readonly users: UserRepository,
  ) {}

  async handle(cmd: RegisterUser): Promise<void> {
    const user = User.register(
      cmd.email,
      await Password.hash(cmd.password),
    );
    await this.users.save(user);
  }
}

Be first to ship with SaaSFormation

We're opening access progressively. Leave your email and we'll reach out when it's your turn.

No spam. Your email is only used to notify you when access opens.