Bundles
The problem
Section titled “The problem”Granit ships 135 packages. That level of granularity is great for control, but overwhelming when you just want to start a new project. You should not have to know the full module graph to get a working API up.
Bundles solve this. A bundle is a meta-package that pulls in a curated set of related modules. One package reference, one Add*() call, and the entire group is wired.
Available bundles
Section titled “Available bundles”| Bundle | Includes | Use case |
|---|---|---|
| Essentials | Core, Timing, Guids, Validation, ExceptionHandling, Observability | Every project |
| Api | Essentials + ApiVersioning, ApiDocumentation, Cors, Idempotency, Cookies | REST API projects |
| Documents | Templating.Scriban, DocumentGeneration.Pdf, DocumentGeneration.Excel | Document generation |
| Notifications | Notifications + Email.Smtp, Sms, Push, SignalR | Multi-channel notifications |
| SaaS | Api + MultiTenancy, Settings, Features, Localization, BackgroundJobs, Caching.Hybrid | Full SaaS platform |
Each bundle is a NuGet meta-package with no code of its own. It only declares dependencies on the modules it groups.
Reference the bundle package and call the corresponding method on the Granit builder:
builder.AddGranit<AppModule>(granit => granit .AddSaaS());builder.AddGranit<AppModule>(granit => granit .AddApi() .AddNotifications() .AddDocuments());GranitBuilder fluent API
Section titled “GranitBuilder fluent API”Bundles are built on the same GranitBuilder fluent API that individual modules use. If a bundle groups more than you need, skip it and pick modules directly:
builder.AddGranit<AppModule>(granit => granit .AddEssentials() .AddModule<GranitTemplatingScribanModule>() .AddModule<GranitDocumentGenerationPdfModule>());This gives you full control without losing the ergonomics of the builder pattern.
Bundles are additive
Section titled “Bundles are additive”You can combine any number of bundles in a single call. Deduplication is automatic: the module dependency graph tracks what is already registered and skips duplicates. Calling .AddSaaS() (which includes Api, which includes Essentials) and then .AddNotifications() works without conflict.
// SaaS already includes Api and Essentials — no duplicatesbuilder.AddGranit<AppModule>(granit => granit .AddSaaS() .AddNotifications() .AddDocuments());When NOT to use bundles
Section titled “When NOT to use bundles”Bundles are convenience, not requirement. If your project only needs two or three specific packages, reference them directly:
<PackageReference Include="Granit.Core" /><PackageReference Include="Granit.Observability" /><PackageReference Include="Granit.ExceptionHandling" />This keeps your dependency footprint minimal and avoids pulling in modules you will never configure.
Further reading
Section titled “Further reading”- Module System — how
DependsOnand the module graph work - Reference overview — per-module API documentation