A comprehensive guide to the modern full-stack development landscape, including the best tools, frameworks, and practices for 2024.
javascript
// app/page.tsx - App Router with Server Components
export default async function HomePage() {
const posts = await getPosts(); // Server-side data fetching
return (
Welcome to My Blog
);
}
javascript
import { create } from 'zustand';
const useStore = create((set) => ({
user: null,
setUser: (user) => set({ user }),
logout: () => set({ user: null })
}));
// Usage in component
function Profile() {
const { user, logout } = useStore();
return (
Welcome, {user?.name}
);
}
jsx

Company retreat
Looking to take your team away on a retreat to enjoy awesome food and take in some sunshine? We have a list of places to do just that.
javascript
import express from 'express';
import { z } from 'zod';
import rateLimit from 'express-rate-limit';
const app = express();
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use(limiter);
app.use(express.json());
// Input validation with Zod
const userSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string().min(2)
});
app.post('/api/users', async (req, res) => {
try {
const userData = userSchema.parse(req.body);
const user = await createUser(userData);
res.json({ user });
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({ errors: error.errors });
}
res.status(500).json({ error: 'Internal server error' });
}
});
prisma
// schema.prisma
model User {
id String @id @default(cuid())
email String @unique
name String
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Post {
id String @id @default(cuid())
title String
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
javascript
// Using Prisma Client
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
// Create user with posts
const user = await prisma.user.create({
data: {
email: 'john@example.com',
name: 'John Doe',
posts: {
create: [
{ title: 'My first post', content: 'Hello world!' },
{ title: 'My second post', content: 'This is great!' }
]
}
},
include: {
posts: true
}
});
javascript
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { prisma } from '@/lib/prisma';
const handler = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!
})
],
callbacks: {
session: async ({ session, token }) => {
if (session?.user) {
session.user.id = token.sub;
}
return session;
},
jwt: async ({ user, token }) => {
if (user) {
token.sub = user.id;
}
return token;
}
}
});
export { handler as GET, handler as POST };
dockerfile
# Multi-stage build for Next.js
FROM node:18-alpine AS base
# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["node", "server.js"]
yaml
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- run: npm ci
- run: npm run test
- run: npm run build
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Vercel
uses: amondnet/vercel-action@v20
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.ORG_ID }}
vercel-project-id: ${{ secrets.PROJECT_ID }}
vercel-args: '--prod'
javascript
// utils.test.ts
import { describe, it, expect } from 'vitest';
import { formatCurrency, validateEmail } from './utils';
describe('Utils', () => {
it('should format currency correctly', () => {
expect(formatCurrency(1234.56)).toBe('$1,234.56');
expect(formatCurrency(0)).toBe('$0.00');
});
it('should validate email addresses', () => {
expect(validateEmail('test@example.com')).toBe(true);
expect(validateEmail('invalid-email')).toBe(false);
});
});
javascript
// tests/auth.spec.ts
import { test, expect } from '@playwright/test';
test('user can sign in and access dashboard', async ({ page }) => {
await page.goto('/login');
await page.fill('[data-testid="email"]', 'test@example.com');
await page.fill('[data-testid="password"]', 'password123');
await page.click('[data-testid="login-button"]');
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('h1')).toContainText('Welcome back');
});
javascript
// Dynamic imports for code splitting
import dynamic from 'next/dynamic';
const DynamicChart = dynamic(() => import('../components/Chart'), {
loading: () => Loading chart...
,
ssr: false
});
function Dashboard() {
return (
Dashboard
);
}
javascript
import Image from 'next/image';
function Hero() {
return (
src="/hero-image.jpg"
alt="Hero image"
fill
className="object-cover"
priority
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
);
}
javascript
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
debug: false,
replaysOnErrorSampleRate: 1.0,
replaysSessionSampleRate: 0.1,
integrations: [
new Sentry.Replay({
maskAllText: true,
blockAllMedia: true
})
]
});
javascript
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react';
export default function RootLayout({ children }) {
return (
{children}
);
}
Full Stack Developer
Passionate full-stack developer and tech consultant helping businesses build scalable solutions and accelerate growth.
Learn the key architectural decisions that can make or break your SaaS application as it scales from 100 to 100,000+ users.
Read MoreIf you enjoyed this article and want to discuss your project or get personalized advice, I'd love to hear from you.