Creer un SaaS avec NestJS et Angular: Guide Complet 2026
J'ai passe 4 mois a construire mon premier SaaS from scratch. Quatre mois a configurer l'authentification, les webhooks Stripe, le multi-tenant, les roles, les emails... et je n'avais meme pas commence a travailler sur la fonctionnalite principale de mon produit. Plus jamais. Aujourd'hui, je vais vous montrer comment eviter cette erreur et lancer votre SaaS en semaines, pas en mois.
Pourquoi NestJS et Angular pour un SaaS en 2026
Construire un SaaS a partir de zero est un defi considerable. Entre la gestion des utilisateurs, la facturation, le multi-tenant et la securite, il faut souvent six mois avant de pouvoir travailler sur la fonctionnalite principale de votre produit.
NestJS et Angular forment un duo particulierement efficace pour les projets SaaS. Ils partagent la meme philosophie architecturale : modules, injection de dependances, decorateurs et TypeScript de bout en bout. Ce que vous apprenez cote frontend se transpose directement cote backend. Pour une analyse detaillee de cette synergie, consultez notre article Pourquoi Angular + NestJS pour le SaaS.
Dans ce guide, nous allons construire les fondations d'une application SaaS complete.
Architecture d'un SaaS moderne
Avant d'ecrire du code, definissons l'architecture cible :
┌─────────────────────────────────────┐
│ Angular Frontend │
│ (Dashboard, Auth, Admin Panel) │
├─────────────────────────────────────┤
│ API Gateway (NestJS) │
│ (Auth, Rate Limiting, Validation) │
├──────────┬──────────┬───────────────┤
│ Module │ Module │ Module │
│ Users │ Billing │ Tenants │
├──────────┴──────────┴───────────────┤
│ PostgreSQL + Redis + S3 │
└─────────────────────────────────────┘
Pour approfondir cette architecture multi-tenant, je recommande notre guide dedie sur l'architecture multi-tenant avec NestJS.
Cloudrix SaaS Starter ships with this pre-configured and tested.
Skip weeks of boilerplate — auth, payments, multi-tenancy, and deployment included out of the box.
Try the live demo →Etape 1 : Initialiser le projet
Creez un workspace Nx pour gerer le frontend et le backend dans un seul depot :
npx create-nx-workspace@latest mon-saas --preset=nest
cd mon-saas
Ajoutez une application Angular :
nx g @nx/angular:app dashboard
Etape 2 : Le module d'authentification
L'authentification est la pierre angulaire de tout SaaS. Implementons JWT avec refresh tokens. Pour un guide complet sur ce sujet, consultez notre article sur l'authentification JWT et OAuth.
// auth/auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './strategies/jwt.strategy';
@Module({
imports: [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.registerAsync({
useFactory: () => ({
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: '15m' },
}),
}),
],
controllers: [AuthController],
providers: [AuthService, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}
Le service d'authentification gere l'inscription, la connexion et le renouvellement des tokens :
// auth/auth.service.ts
@Injectable()
export class AuthService {
constructor(
private readonly jwtService: JwtService,
private readonly usersService: UsersService,
) {}
async inscription(dto: InscriptionDto) {
const motDePasseHash = await bcrypt.hash(dto.motDePasse, 12);
const utilisateur = await this.usersService.creer({
email: dto.email,
motDePasse: motDePasseHash,
nom: dto.nom,
});
const tokens = await this.genererTokens(utilisateur);
return { utilisateur, ...tokens };
}
async connexion(dto: ConnexionDto) {
const utilisateur = await this.usersService
.trouverParEmail(dto.email);
if (!utilisateur) {
throw new UnauthorizedException('Identifiants invalides');
}
const motDePasseValide = await bcrypt.compare(
dto.motDePasse,
utilisateur.motDePasse,
);
if (!motDePasseValide) {
throw new UnauthorizedException('Identifiants invalides');
}
return this.genererTokens(utilisateur);
}
private async genererTokens(utilisateur: Utilisateur) {
const payload = {
sub: utilisateur.id,
email: utilisateur.email,
tenantId: utilisateur.tenantId,
};
return {
accessToken: this.jwtService.sign(payload),
refreshToken: this.jwtService.sign(payload, {
expiresIn: '7d',
}),
};
}
}
Mon conseil : Ne stockez jamais les tokens JWT dans le
localStorageen production. Utilisez des cookieshttpOnlyavec le flagsecure. C'est un detail que beaucoup de tutoriels ignorent, mais qui fait la difference entre un SaaS amateur et un SaaS professionnel.
Etape 3 : Multi-tenancy par schema
Pour un SaaS, chaque client doit avoir ses donnees isolees. L'approche par schema PostgreSQL offre un bon equilibre entre isolation et simplicite. Nous avons un guide complet sur le sujet : TypeORM Multi-Tenancy avec PostgreSQL.
// tenancy/tenant.middleware.ts
@Injectable()
export class TenantMiddleware implements NestMiddleware {
constructor(private readonly connection: Connection) {}
async use(req: Request, res: Response, next: NextFunction) {
const tenantId = req.headers['x-tenant-id'] as string;
if (!tenantId) {
throw new BadRequestException('Tenant ID requis');
}
const schemaName = `tenant_${tenantId}`;
await this.connection.query(`SET search_path TO "${schemaName}"`);
req['tenantId'] = tenantId;
next();
}
}
🚀 Vous voulez sauter ces semaines de configuration ? Le Cloudrix SaaS Starter inclut l'authentification JWT, le multi-tenant, Stripe, les roles RBAC et le deploiement Docker -- tout est deja configure et teste. Testez la demo en direct.
Etape 4 : Integration Stripe pour les paiements
Les abonnements sont le coeur financier d'un SaaS. Voici comment integrer Stripe (pour un guide approfondi, consultez notre guide complet d'integration Stripe) :
// billing/billing.service.ts
@Injectable()
export class BillingService {
private stripe: Stripe;
constructor() {
this.stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
}
async creerAbonnement(
clientId: string,
planId: string,
) {
const abonnement = await this.stripe.subscriptions.create({
customer: clientId,
items: [{ price: planId }],
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
});
return {
abonnementId: abonnement.id,
clientSecret: (abonnement.latest_invoice as Stripe.Invoice)
.payment_intent.client_secret,
};
}
async gererWebhook(payload: Buffer, signature: string) {
const event = this.stripe.webhooks.constructEvent(
payload,
signature,
process.env.STRIPE_WEBHOOK_SECRET,
);
switch (event.type) {
case 'invoice.payment_succeeded':
await this.activerAbonnement(event.data.object);
break;
case 'customer.subscription.deleted':
await this.desactiverAbonnement(event.data.object);
break;
}
}
}
Etape 5 : Le dashboard Angular
Cote frontend, creez un dashboard avec routing protege. Si vous souhaitez construire un dashboard complet, notre guide sur le dashboard admin Angular est une excellente ressource.
// app.routes.ts
export const routes: Routes = [
{
path: 'auth',
loadChildren: () => import('./auth/auth.routes')
.then(m => m.AUTH_ROUTES),
},
{
path: 'dashboard',
canActivate: [authGuard],
loadChildren: () => import('./dashboard/dashboard.routes')
.then(m => m.DASHBOARD_ROUTES),
},
];
Utilisez les Signals Angular pour gerer l'etat de l'utilisateur. Pour en savoir plus sur cette approche, lisez notre article sur le state management avec Angular Signals.
// auth/auth.store.ts
@Injectable({ providedIn: 'root' })
export class AuthStore {
private utilisateurSignal = signal<Utilisateur | null>(null);
private chargementSignal = signal(false);
readonly utilisateur = this.utilisateurSignal.asReadonly();
readonly estConnecte = computed(() =>
this.utilisateurSignal() !== null
);
readonly chargement = this.chargementSignal.asReadonly();
async connexion(email: string, motDePasse: string) {
this.chargementSignal.set(true);
try {
const response = await this.authService
.connexion({ email, motDePasse });
this.utilisateurSignal.set(response.utilisateur);
localStorage.setItem('token', response.accessToken);
} finally {
this.chargementSignal.set(false);
}
}
}
Etape 6 : Deploiement
Pour la production, utilisez Docker Compose pour orchestrer les services. Notre guide Docker Compose pour NestJS et Angular couvre ce sujet en detail.
# docker-compose.prod.yml
services:
api:
build:
context: .
dockerfile: apps/api/Dockerfile
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/saas
- JWT_SECRET=${JWT_SECRET}
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
ports:
- "3000:3000"
dashboard:
build:
context: .
dockerfile: apps/dashboard/Dockerfile
ports:
- "4200:80"
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
Pour un deploiement sur AWS avec Terraform, consultez notre guide complet de deploiement NestJS + Angular sur AWS.
Gagner des mois de developpement 💡
Ce guide couvre les fondations, mais un SaaS en production necessite bien plus : gestion des roles (RBAC), emails transactionnels, audit logs, rate limiting, conformite RGPD, et des dizaines d'autres fonctionnalites.
SaaS Starter est un boilerplate NestJS + Angular qui inclut tout cela, pret a l'emploi. La version Lite est disponible gratuitement sur GitHub pour demarrer immediatement. Pour voir l'ensemble des fonctionnalites en action, y compris le multi-tenant, l'integration Stripe et le panneau d'administration, visitez la demo en direct.
Je l'utilise moi-meme pour mes propres projets, et il m'a fait gagner litteralement des mois de developpement. Concentrez-vous sur ce qui rend votre produit unique -- laissez l'infrastructure a un boilerplate eprouve.
Pret a commencer ? Essayez la demo | Consultez les tarifs -- la version Lite est entierement gratuite.