The terms stateful and stateless describe whether a system or component maintains context (state) between interactions (such as API calls, sessions, or processes).
π Stateful
A stateful system remembers previous interactions. It maintains data (state) across requests or sessions.
β Characteristics:
- Stores session info between requests.
- Requires memory/persistence layer (e.g., session store, database, in-memory cache).
- Ideal for long-lived workflows or real-time interactions (e.g., chat, streaming, games).
π¦ Examples:
-
Stateful API: A login session stored on the server (e.g.,
express-session
with Redis). - WebSocket connection: Keeps user state alive during a conversation.
- Database connection pools: Keep the connection state between requests.
β οΈ Downsides:
- Harder to scale (e.g., sticky sessions or external session store needed).
- Higher memory usage and complexity in distributed systems.
π Stateless
A stateless system forgets each interaction. Every request is treated independently and must contain all the needed information.
β Characteristics:
- No stored session data on the server.
- Easy to scale horizontally.
- More fault-tolerant and simple in cloud-native architectures.
π¦ Examples:
- RESTful APIs: Every request must be self-contained (e.g., auth token in headers).
- JWT Authentication: All session info is stored client-side in the token.
- Serverless functions (e.g., AWS Lambda): Cold start = no memory of past calls.
β οΈ Trade-offs:
- More data passed per request (e.g., token, context).
- Harder to implement certain types of interactions (e.g., chat history, multi-step workflows).
π§ Analogy
Imagine a stateless waiter in a restaurant. Every time you want something, you must reintroduce yourself and re-explain your order.
A stateful waiter remembers your table, your name, and your drink order β theyβre context-aware.
π§ In a Fullstack GenAI App
Component | Stateless or Stateful | Why? |
---|---|---|
REST API (NestJS) | Stateless | Easier to scale, authenticate using JWT. |
WebSocket Chat | Stateful | Needs to keep track of user sessions, conversation threads. |
AI Context Memory | Hybrid (stateless requests, stateful memory) | You might store conversation history in Redis or a DB for context replay. |
Frontend (Next.js) | Mostly Stateless (per request) | But stateful per session in the browser (via React state, cookies, localStorage). |
Example
stateful vs stateless authentication with NESTJS
π 1. Stateless Authentication (JWT-based)
Best for: scalable, distributed systems (e.g., REST APIs, microservices).
π§ Concept:
- User logs in, receives a JWT token.
- Token is sent with every request (usually via
Authorization: Bearer <token>
header). - Server doesn't store session β it just verifies the token.
β Stateless Auth β NestJS Example
1. Auth Module Setup
// auth.module.ts
@Module({
imports: [
JwtModule.register({
secret: process.env.JWT_SECRET,
signOptions: { expiresIn: '1h' },
}),
PassportModule,
],
providers: [AuthService, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}
2. JWT Strategy
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_SECRET,
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}
3. Guard & Decorator
// jwt-auth.guard.ts
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
// usage in controller
@UseGuards(JwtAuthGuard)
@Get('profile')
getProfile(@Request() req) {
return req.user;
}
π§© 2. Stateful Authentication (Session + Cookie-based)
Best for: monoliths, internal apps, or SSR apps where the backend and frontend share session context.
π§ Concept:
- User logs in β server stores session in-memory or in Redis.
- Client gets a session cookie (
Set-Cookie
). - Server uses the cookie to look up session data on each request.
β
Stateful Auth β NestJS Example (with express-session
)
1. Install dependencies:
npm install express-session @nestjs/passport passport passport-local
2. Main.ts Setup
// main.ts
import * as session from 'express-session';
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { secure: false }, // true if using HTTPS
}),
);
For distributed apps, add a Redis store:
import * as RedisStore from 'connect-redis';
import { createClient } from 'redis';
const redisClient = createClient();
await redisClient.connect();
app.use(
session({
store: new (RedisStore(session))({ client: redisClient }),
...
}),
);
3. Passport Session Setup
// auth.service.ts
async validateUser(username: string, password: string): Promise<any> {
const user = await this.userService.findByUsername(username);
if (user && user.password === password) return user;
return null;
}
// local.strategy.ts
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super();
}
async validate(username: string, password: string): Promise<any> {
const user = await this.authService.validateUser(username, password);
if (!user) throw new UnauthorizedException();
return user;
}
}
// auth.controller.ts
@UseGuards(LocalAuthGuard)
@Post('login')
login(@Request() req) {
// Session is now stored; req.session is available
return req.user;
}
@Get('profile')
getProfile(@Request() req) {
return req.user; // comes from session
}
π§ Summary Table
Feature | Stateless (JWT) | Stateful (Session + Cookie) |
---|---|---|
Server stores session? | β No | β Yes (Memory/Redis) |
Scalability | β Great (easy scaling) | β οΈ Sticky sessions or shared store |
Auth header required? | β Yes (Bearer token) | β No, browser handles cookies |
Suited for | APIs, SPAs | SSR apps, internal tools |
Token expiry? | β Client-controlled | β Server-controlled |
Revocation (logout)? | β Hard (need token blacklist) | β Easy (delete session) |
βοΈ When to Use What in NestJS GenAI App?
Use Case | Recommendation |
---|---|
AI dictionary API (mobile or SPA) | β JWT (stateless) |
Admin dashboard (SSR in Next.js) | β Session (stateful) |
Real-time chat / conversation memory | π§ Hybrid (stateful for chat memory, JWT for auth) |
Top comments (2)
Pretty cool breakdown, honestly always makes me rethink how I set up auth every single time.
Loved the restaurant analogy! It really makes the stateful vs stateless concept click. Super clear breakdownβthanks!
Some comments may only be visible to logged-in visitors. Sign in to view all comments.