Skip to content

Bundles

Granit ships 164 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.

BundleIncludesUse case
EssentialsCore, Timing, Guids, Validation, ExceptionHandling, ObservabilityEvery project
ApiEssentials + ApiVersioning, ApiDocumentation, Cors, Idempotency, CookiesREST API projects
DocumentsTemplating.Scriban, DocumentGeneration.Pdf, DocumentGeneration.ExcelDocument generation
NotificationsNotifications + Email.Smtp, Sms, Push, SignalRMulti-channel notifications
SaaSApi + MultiTenancy, Settings, Features, Localization, BackgroundJobs, Caching.HybridFull SaaS platform

Each bundle is a NuGet meta-package with no code of its own. It only declares dependencies on the modules it groups.

PackageEssentialsApiNotificationsDocumentsSaaS
Granit.Core
Granit.Timing
Granit.Guids
Granit.Validation
Granit.ExceptionHandling
Granit.Observability
Granit.ApiVersioning
Granit.ApiDocumentation
Granit.Cors
Granit.Idempotency
Granit.Cookies
Granit.Notifications
Granit.Notifications.Email.Smtp
Granit.Notifications.Sms
Granit.Notifications.Push
Granit.Notifications.SignalR
Granit.Templating.Scriban
Granit.DocumentGeneration.Pdf
Granit.DocumentGeneration.Excel
Granit.MultiTenancy
Granit.Settings
Granit.Features
Granit.Localization
Granit.BackgroundJobs
Granit.Caching.Hybrid

SaaS inherits everything in Api, which inherits everything in Essentials. The Notifications and Documents bundles are standalone — add them on top of any base.

Reference the bundle package and call the corresponding method on the Granit builder:

builder.AddGranit<AppModule>(granit => granit
.AddSaaS());

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.

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 duplicates
builder.AddGranit<AppModule>(granit => granit
.AddSaaS()
.AddNotifications()
.AddDocuments());

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.