Files
claude-skills-reference/engineering-team/senior-fullstack/references/tech_stack_guide.md
Alireza Rezvani 888ad9b584 fix(skill): rewrite senior-fullstack with real fullstack content (#67) (#127)
- Replace placeholder project_scaffolder.py with real implementation
  supporting Next.js, FastAPI+React, MERN, Django+React templates
- Replace placeholder code_quality_analyzer.py with real implementation
  for security, complexity, dependencies, and test coverage analysis
- Delete redundant fullstack_scaffolder.py (functionality in project_scaffolder)
- Rewrite architecture_patterns.md with real patterns:
  frontend architecture, backend patterns, API design, caching, auth
- Rewrite development_workflows.md with real workflows:
  Docker setup, git workflows, CI/CD, testing, deployment strategies
- Rewrite tech_stack_guide.md with real comparisons:
  framework selection, database choices, auth solutions, deployment
- Rewrite SKILL.md with TOC, trigger phrases, actual tool parameters

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 09:11:07 +01:00

14 KiB

Fullstack Tech Stack Guide

Technology selection guide with trade-offs, use cases, and integration patterns for modern fullstack development.


Table of Contents


Frontend Frameworks

Next.js

Best for: Production React apps, SEO-critical sites, full-stack applications

Pros Cons
Server components, streaming Learning curve for advanced features
Built-in routing, API routes Vercel lock-in concerns
Excellent DX and performance Bundle size can grow
Strong TypeScript support Complex mental model (client/server)

When to choose:

  • Need SSR/SSG for SEO
  • Building a product that may scale
  • Want full-stack in one framework
  • Team familiar with React
// App Router pattern
// app/users/page.tsx
async function UsersPage() {
  const users = await db.user.findMany(); // Server component
  return <UserList users={users} />;
}

// app/users/[id]/page.tsx
export async function generateStaticParams() {
  const users = await db.user.findMany();
  return users.map((user) => ({ id: user.id }));
}

React + Vite

Best for: SPAs, dashboards, internal tools

Pros Cons
Fast development with HMR No SSR out of the box
Simple mental model Manual routing setup
Flexible architecture No built-in API routes
Smaller bundle potential Need separate backend

When to choose:

  • Building internal dashboards
  • SEO not important
  • Need maximum flexibility
  • Prefer decoupled frontend/backend

Vue 3

Best for: Teams transitioning from jQuery, progressive enhancement

Pros Cons
Gentle learning curve Smaller ecosystem than React
Excellent documentation Fewer enterprise adoptions
Single-file components Composition API learning curve
Good TypeScript support Two paradigms (Options/Composition)

When to choose:

  • Team new to modern frameworks
  • Progressive enhancement needed
  • Prefer official solutions (Pinia, Vue Router)

Comparison Matrix

Feature Next.js React+Vite Vue 3 Svelte
SSR Built-in Manual Nuxt SvelteKit
Bundle size Medium Small Small Smallest
Learning curve Medium Low Low Low
Enterprise adoption High High Medium Low
Job market Large Large Medium Small

Backend Frameworks

Node.js Ecosystem

Express.js

import express from "express";
import { userRouter } from "./routes/users";

const app = express();
app.use(express.json());
app.use("/api/users", userRouter);
app.listen(3000);
Pros Cons
Minimal, flexible No structure opinions
Huge middleware ecosystem Callback-based (legacy)
Well understood Manual TypeScript setup

Fastify

import Fastify from "fastify";

const app = Fastify({ logger: true });

app.get("/users/:id", {
  schema: {
    params: { type: "object", properties: { id: { type: "string" } } },
    response: { 200: UserSchema },
  },
  handler: async (request) => {
    return db.user.findUnique({ where: { id: request.params.id } });
  },
});
Pros Cons
High performance Smaller ecosystem
Built-in validation Different plugin model
TypeScript-first Less community content

NestJS

@Controller("users")
export class UsersController {
  constructor(private usersService: UsersService) {}

  @Get(":id")
  findOne(@Param("id") id: string) {
    return this.usersService.findOne(id);
  }

  @Post()
  @UseGuards(AuthGuard)
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }
}
Pros Cons
Strong architecture Steep learning curve
Full-featured (GraphQL, WebSockets) Heavy for small projects
Enterprise-ready Decorator complexity

Python Ecosystem

FastAPI

from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session

app = FastAPI()

@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404)
    return user
Pros Cons
Auto-generated docs Python GIL limitations
Type hints → validation Async ecosystem maturing
High performance Smaller than Django ecosystem

Django

Pros Cons
Batteries included Monolithic
Admin panel ORM limitations
Mature ecosystem Async support newer

Framework Selection Guide

Use Case Recommendation
API-first startup FastAPI or Fastify
Enterprise backend NestJS or Django
Microservices Fastify or Go
Rapid prototype Express or Django
Full-stack TypeScript Next.js API routes

Databases

PostgreSQL

Best for: Most applications, relational data, ACID compliance

-- JSON support
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email VARCHAR(255) UNIQUE NOT NULL,
  profile JSONB DEFAULT '{}',
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Full-text search
CREATE INDEX users_search_idx ON users
  USING GIN (to_tsvector('english', email || ' ' || profile->>'name'));

SELECT * FROM users
WHERE to_tsvector('english', email || ' ' || profile->>'name')
  @@ to_tsquery('john');
Feature Rating
ACID compliance Excellent
JSON support Excellent
Full-text search Good
Horizontal scaling Requires setup
Managed options Many (RDS, Supabase, Neon)

MongoDB

Best for: Document-heavy apps, flexible schemas, rapid prototyping

// Flexible schema
const userSchema = new Schema({
  email: { type: String, required: true, unique: true },
  profile: {
    name: String,
    preferences: Schema.Types.Mixed, // Any structure
  },
  orders: [{ type: Schema.Types.ObjectId, ref: "Order" }],
});
Feature Rating
Schema flexibility Excellent
Horizontal scaling Excellent
Transactions Good (4.0+)
Joins Limited
Managed options Atlas

Redis

Best for: Caching, sessions, real-time features, queues

// Session storage
await redis.set(`session:${sessionId}`, JSON.stringify(user), "EX", 3600);

// Rate limiting
const requests = await redis.incr(`rate:${ip}`);
if (requests === 1) await redis.expire(`rate:${ip}`, 60);
if (requests > 100) throw new TooManyRequestsError();

// Pub/Sub
redis.publish("notifications", JSON.stringify({ userId, message }));

Database Selection Matrix

Requirement PostgreSQL MongoDB MySQL
Complex queries Best Limited Good
Schema flexibility Good (JSONB) Best Limited
Transactions Best Good Good
Horizontal scale Manual Built-in Manual
Cloud managed Many Atlas Many

ORMs and Query Builders

Prisma

Best for: TypeScript projects, schema-first development

// schema.prisma
model User {
  id        String   @id @default(cuid())
  email     String   @unique
  posts     Post[]
  profile   Profile?
  createdAt DateTime @default(now())
}

// Usage - fully typed
const user = await prisma.user.findUnique({
  where: { email: "user@example.com" },
  include: { posts: true, profile: true },
});
// user.posts is Post[] - TypeScript knows
Pros Cons
Excellent TypeScript Generated client size
Schema migrations Limited raw SQL support
Visual studio Some edge case limitations

Drizzle

Best for: SQL-first TypeScript, performance-critical apps

// Schema definition
const users = pgTable("users", {
  id: uuid("id").primaryKey().defaultRandom(),
  email: varchar("email", { length: 255 }).notNull().unique(),
  createdAt: timestamp("created_at").defaultNow(),
});

// Query - SQL-like syntax
const result = await db
  .select()
  .from(users)
  .where(eq(users.email, "user@example.com"))
  .leftJoin(posts, eq(posts.userId, users.id));
Pros Cons
Lightweight Newer, smaller community
SQL-like syntax Fewer integrations
Fast runtime Manual migrations

SQLAlchemy (Python)

# Model definition
class User(Base):
    __tablename__ = "users"

    id = Column(UUID, primary_key=True, default=uuid4)
    email = Column(String(255), unique=True, nullable=False)
    posts = relationship("Post", back_populates="author")

# Query
users = session.query(User)\
    .filter(User.email.like("%@example.com"))\
    .options(joinedload(User.posts))\
    .all()

Authentication Solutions

Auth.js (NextAuth)

Best for: Next.js apps, social logins

// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
import Credentials from "next-auth/providers/credentials";

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [
    GitHub,
    Credentials({
      credentials: { email: {}, password: {} },
      authorize: async (credentials) => {
        const user = await verifyCredentials(credentials);
        return user;
      },
    }),
  ],
  callbacks: {
    jwt({ token, user }) {
      if (user) token.role = user.role;
      return token;
    },
  },
});
Pros Cons
Many providers Next.js focused
Session management Complex customization
Database adapters Breaking changes between versions

Clerk

Best for: Rapid development, hosted solution

// Middleware
import { clerkMiddleware } from "@clerk/nextjs/server";

export default clerkMiddleware();

// Usage
import { auth } from "@clerk/nextjs/server";

export async function GET() {
  const { userId } = await auth();
  if (!userId) return new Response("Unauthorized", { status: 401 });
  // ...
}
Pros Cons
Beautiful UI components Vendor lock-in
Managed infrastructure Cost at scale
Multi-factor auth Data residency concerns

Custom JWT

Best for: Full control, microservices

// Token generation
function generateTokens(user: User) {
  const accessToken = jwt.sign(
    { sub: user.id, role: user.role },
    process.env.JWT_SECRET,
    { expiresIn: "15m" }
  );

  const refreshToken = jwt.sign(
    { sub: user.id, version: user.tokenVersion },
    process.env.REFRESH_SECRET,
    { expiresIn: "7d" }
  );

  return { accessToken, refreshToken };
}

// Middleware
function authenticate(req, res, next) {
  const token = req.headers.authorization?.replace("Bearer ", "");
  if (!token) return res.status(401).json({ error: "No token" });

  try {
    req.user = jwt.verify(token, process.env.JWT_SECRET);
    next();
  } catch {
    res.status(401).json({ error: "Invalid token" });
  }
}

Deployment Platforms

Vercel

Best for: Next.js, frontend-focused teams

Pros Cons
Zero-config Next.js Expensive at scale
Edge functions Vendor lock-in
Preview deployments Limited backend options
Global CDN Cold starts

Railway

Best for: Full-stack apps, databases included

Pros Cons
Simple deployment Smaller community
Built-in databases Limited regions
Good pricing Fewer integrations

AWS (ECS/Lambda)

Best for: Enterprise, complex requirements

Pros Cons
Full control Complex setup
Cost-effective at scale Steep learning curve
Any technology Requires DevOps knowledge

Deployment Selection

Requirement Platform
Next.js simplicity Vercel
Full-stack + DB Railway, Render
Enterprise scale AWS, GCP
Container control Fly.io, Railway
Budget startup Railway, Render

Stack Recommendations

Startup MVP

Frontend: Next.js 14 (App Router)
Backend:  Next.js API Routes
Database: PostgreSQL (Neon/Supabase)
Auth:     Auth.js or Clerk
Deploy:   Vercel
Cache:    Vercel KV or Upstash Redis

Why: Fastest time to market, single deployment, good scaling path.

SaaS Product

Frontend: Next.js 14
Backend:  Separate API (FastAPI or NestJS)
Database: PostgreSQL (RDS)
Auth:     Custom JWT + Auth.js
Deploy:   Vercel (frontend) + AWS ECS (backend)
Cache:    Redis (ElastiCache)
Queue:    SQS or BullMQ

Why: Separation allows independent scaling, team specialization.

Enterprise Application

Frontend: Next.js or React + Vite
Backend:  NestJS or Go
Database: PostgreSQL (Aurora)
Auth:     Keycloak or Auth0
Deploy:   Kubernetes (EKS/GKE)
Cache:    Redis Cluster
Queue:    Kafka or RabbitMQ
Observability: Datadog or Grafana Stack

Why: Maximum control, compliance requirements, team expertise.

Internal Tool

Frontend: React + Vite + Tailwind
Backend:  Express or FastAPI
Database: PostgreSQL or SQLite
Auth:     OIDC with corporate IdP
Deploy:   Docker on internal infrastructure

Why: Simple, low maintenance, integrates with existing systems.


Quick Decision Guide

Question If Yes → If No →
Need SEO? Next.js SSR React SPA
Complex backend? Separate API Next.js routes
Team knows Python? FastAPI Node.js
Need real-time? Add WebSockets REST is fine
Enterprise compliance? Self-hosted Managed services
Budget constrained? Railway/Render Vercel/AWS
Schema changes often? MongoDB PostgreSQL