Backend Architecture
Overview
Backend architecture encompasses the server-side decisions that determine how a system stores data, exposes functionality, handles security, and scales under load. The choices made at this level -- API style, database type, caching strategy, authentication mechanism -- ripple through every layer of the application and are difficult to change once established.
This skill provides a decision-making framework drawn from Martin Kleppmann's Designing Data-Intensive Applications and industry-proven patterns for building reliable, scalable, and maintainable backend systems.
Knowledge Map
┌─────────────────────────────────────────────────────────────────┐
│ API Layer │
│ REST, GraphQL, gRPC, WebSocket │
│ → How clients communicate with the backend │
├─────────────────────────────────────────────────────────────────┤
│ Data Storage │ Caching │
│ Relational, Document, Graph, │ In-memory, Distributed, │
│ Key-Value, Time-Series │ CDN, HTTP caching │
│ → How data is persisted │ → How hot data is served │
├─────────────────────────────────────────────────────────────────┤
│ Authentication & Authorization │ Background Processing │
│ OAuth 2.0, JWT, RBAC, ABAC, │ Job queues, schedulers, │
│ Multi-tenancy │ event-driven workers │
├─────────────────────────────────────────────────────────────────┤
│ Rate Limiting & Throttling │ Observability │
│ Token bucket, sliding window, │ Logging, metrics, tracing, │
│ API quotas, circuit breakers │ health checks, alerting │
└─────────────────────────────────────────────────────────────────┘
Choosing an API Style
| Criterion |
REST |
GraphQL |
gRPC |
WebSocket |
| Best for |
CRUD resources, public APIs |
Flexible queries, mobile clients |
Internal microservices, high throughput |
Real-time bidirectional communication |
| Data format |
JSON (typically) |
JSON |
Protobuf (binary) |
Any (JSON, binary) |
| Contract |
OpenAPI / Swagger |
Schema (SDL) |
.proto files |
No standard schema |
| Caching |
HTTP caching (excellent) |
Harder (POST-based) |
No HTTP caching |
Not cacheable |
| Streaming |
SSE (server-only) |
Subscriptions |
Bidirectional streaming |
Full-duplex native |
| Browser support |
Native |
Native |
Requires gRPC-Web proxy |
Native |
| Learning curve |
Low |
Medium |
Medium-High |
Low-Medium |
| Over/under-fetching |
Common problem |
Solved by design |
Defined per RPC |
N/A |
| Tooling maturity |
Excellent |
Good |
Good (growing) |
Moderate |
Decision heuristic:
- Default to REST for public APIs and simple CRUD services.
- Choose GraphQL when clients need flexible, aggregated queries across multiple resources (especially mobile).
- Choose gRPC for internal service-to-service communication where latency and throughput matter.
- Choose WebSocket when you need real-time, bidirectional data flow (chat, live dashboards, collaborative editing).
- Many systems combine styles: REST for public API, gRPC internally, WebSocket for real-time features.
Choosing a Database Type
| Criterion |
Relational (SQL) |
Document (NoSQL) |
Graph |
Key-Value |
Time-Series |
| Best for |
Structured data, complex joins, ACID transactions |
Flexible schemas, nested data, rapid iteration |
Highly connected data, relationship traversal |
Simple lookups, caching, session storage |
Metrics, IoT, logs, financial ticks |
| Examples |
PostgreSQL, MySQL, SQL Server |
MongoDB, CouchDB, DynamoDB |
Neo4j, Amazon Neptune, ArangoDB |
Redis, Memcached, DynamoDB |
InfluxDB, TimescaleDB, Prometheus |
| Schema |
Strict (schema-on-write) |
Flexible (schema-on-read) |
Property graph / RDF |
Schema-free |
Tag + field model |
| Scaling |
Vertical (horizontal with sharding) |
Horizontal (built-in) |
Vertical (some horizontal) |
Horizontal (built-in) |
Horizontal (built-in) |
| Transactions |
Full ACID |
Limited (document-level) |
Varies by product |
None (typically) |
None (typically) |
| Query language |
SQL |
Vendor-specific (MQL, etc.) |
Cypher, Gremlin, SPARQL |
GET/SET commands |
InfluxQL, Flux, SQL |
| Joins |
Excellent |
Poor (application-level) |
Excellent (traversals) |
None |
Limited |
Decision heuristic:
- Default to relational (PostgreSQL) when data is structured and relationships matter.
- Choose document when schema flexibility and developer velocity are priorities, and joins are rare.
- Choose graph when the primary queries traverse relationships (social networks, recommendations, fraud detection).
- Choose key-value for caching, sessions, and simple lookup-by-key workloads.
- Choose time-series for append-heavy, time-stamped data with downsampling and retention needs.
- Polyglot persistence is common: use the right database for each bounded context.
Backend Architecture Concerns
Rate Limiting & Throttling
Protect backend services from abuse and overload:
- Token Bucket -- allows bursts up to a configured capacity, refills at a steady rate.
- Sliding Window -- counts requests in a rolling time window for smoother limiting.
- Fixed Window -- simple counter per time window (risk of burst at window boundaries).
- Leaky Bucket -- processes requests at a constant rate, queuing excess.
- Implement at the API gateway layer for consistency across services.
Background Processing
Offload long-running or non-urgent work from the request/response cycle:
- Job queues (Sidekiq, Celery, Hangfire, BullMQ) -- enqueue work, process asynchronously.
- Scheduled jobs (cron, Quartz, Hangfire recurring) -- time-triggered processing.
- Event-driven workers -- react to domain events from a message broker.
- Batch processing -- periodic bulk operations (ETL, report generation).
- Always design for idempotency -- workers may process the same job more than once.
Observability
The three pillars of observability, plus health monitoring:
- Logging -- structured logs (JSON) with correlation IDs for request tracing.
- Metrics -- counters, gauges, histograms (request rate, error rate, latency percentiles).
- Distributed Tracing -- end-to-end trace across services (OpenTelemetry, Jaeger, Zipkin).
- Health checks -- liveness (is the process running?) and readiness (can it serve traffic?).
- Alerting -- thresholds on key metrics (error rate > 1%, p99 latency > 500ms).
Canonical Reference
- Designing Data-Intensive Applications by Martin Kleppmann -- the definitive guide to data storage, replication, partitioning, encoding, and distributed system trade-offs. Essential reading for any backend architect.
Sub-Skills
dev/backend/data-modeling -- Data modeling and database architecture patterns
dev/backend/api-design -- API design patterns for REST, GraphQL, gRPC, WebSocket
dev/backend/caching -- Caching strategies and patterns
dev/backend/authentication -- Authentication and authorization patterns
Best Practices
- Start with a monolith and extract services only when complexity demands it -- premature microservices add coordination cost without proportional benefit.
- Choose boring technology by default. PostgreSQL, Redis, and a well-designed REST API solve the vast majority of backend problems.
- Design for failure: every network call can fail, every database can be slow. Use timeouts, retries with backoff, circuit breakers, and fallbacks.
- Make operations idempotent wherever possible -- especially for writes, background jobs, and event handlers.
- Instrument everything from day one. Adding observability retroactively is far more expensive than building it in.
- Treat API contracts as public commitments: version explicitly, deprecate gracefully, never break existing clients without a migration path.
1---2name: backend3description: |4 Use when making backend architecture decisions — choosing API styles, database types, caching strategies, authentication mechanisms, and server-side design patterns for scalable, maintainable systems.5 USE FOR: backend architecture decisions, choosing API styles, choosing database types, server-side design patterns, backend system design6 DO NOT USE FOR: specific pattern details (use sub-skills: data-modeling, api-design, caching, authentication), frontend architecture (use dev/frontend), infrastructure (use iac)7license: MIT8metadata:9 displayName: "Backend Architecture"10 author: "Tyler-R-Kendrick"11compatibility: claude, copilot, cursor12references:13 - title: "Martin Fowler — Patterns of Enterprise Application Architecture"14 url: "https://martinfowler.com/eaaCatalog/"15 - title: "OpenAPI Specification"16 url: "https://www.openapis.org/"17---1819# Backend Architecture2021## Overview22Backend architecture encompasses the server-side decisions that determine how a system stores data, exposes functionality, handles security, and scales under load. The choices made at this level -- API style, database type, caching strategy, authentication mechanism -- ripple through every layer of the application and are difficult to change once established.2324This skill provides a decision-making framework drawn from Martin Kleppmann's *Designing Data-Intensive Applications* and industry-proven patterns for building reliable, scalable, and maintainable backend systems.2526## Knowledge Map2728```29┌─────────────────────────────────────────────────────────────────┐30│ API Layer │31│ REST, GraphQL, gRPC, WebSocket │32│ → How clients communicate with the backend │33├─────────────────────────────────────────────────────────────────┤34│ Data Storage │ Caching │35│ Relational, Document, Graph, │ In-memory, Distributed, │36│ Key-Value, Time-Series │ CDN, HTTP caching │37│ → How data is persisted │ → How hot data is served │38├─────────────────────────────────────────────────────────────────┤39│ Authentication & Authorization │ Background Processing │40│ OAuth 2.0, JWT, RBAC, ABAC, │ Job queues, schedulers, │41│ Multi-tenancy │ event-driven workers │42├─────────────────────────────────────────────────────────────────┤43│ Rate Limiting & Throttling │ Observability │44│ Token bucket, sliding window, │ Logging, metrics, tracing, │45│ API quotas, circuit breakers │ health checks, alerting │46└─────────────────────────────────────────────────────────────────┘47```4849## Choosing an API Style5051| Criterion | REST | GraphQL | gRPC | WebSocket |52|-----------|------|---------|------|-----------|53| **Best for** | CRUD resources, public APIs | Flexible queries, mobile clients | Internal microservices, high throughput | Real-time bidirectional communication |54| **Data format** | JSON (typically) | JSON | Protobuf (binary) | Any (JSON, binary) |55| **Contract** | OpenAPI / Swagger | Schema (SDL) | .proto files | No standard schema |56| **Caching** | HTTP caching (excellent) | Harder (POST-based) | No HTTP caching | Not cacheable |57| **Streaming** | SSE (server-only) | Subscriptions | Bidirectional streaming | Full-duplex native |58| **Browser support** | Native | Native | Requires gRPC-Web proxy | Native |59| **Learning curve** | Low | Medium | Medium-High | Low-Medium |60| **Over/under-fetching** | Common problem | Solved by design | Defined per RPC | N/A |61| **Tooling maturity** | Excellent | Good | Good (growing) | Moderate |6263**Decision heuristic:**64- Default to **REST** for public APIs and simple CRUD services.65- Choose **GraphQL** when clients need flexible, aggregated queries across multiple resources (especially mobile).66- Choose **gRPC** for internal service-to-service communication where latency and throughput matter.67- Choose **WebSocket** when you need real-time, bidirectional data flow (chat, live dashboards, collaborative editing).68- Many systems combine styles: REST for public API, gRPC internally, WebSocket for real-time features.6970## Choosing a Database Type7172| Criterion | Relational (SQL) | Document (NoSQL) | Graph | Key-Value | Time-Series |73|-----------|------------------|-------------------|-------|-----------|-------------|74| **Best for** | Structured data, complex joins, ACID transactions | Flexible schemas, nested data, rapid iteration | Highly connected data, relationship traversal | Simple lookups, caching, session storage | Metrics, IoT, logs, financial ticks |75| **Examples** | PostgreSQL, MySQL, SQL Server | MongoDB, CouchDB, DynamoDB | Neo4j, Amazon Neptune, ArangoDB | Redis, Memcached, DynamoDB | InfluxDB, TimescaleDB, Prometheus |76| **Schema** | Strict (schema-on-write) | Flexible (schema-on-read) | Property graph / RDF | Schema-free | Tag + field model |77| **Scaling** | Vertical (horizontal with sharding) | Horizontal (built-in) | Vertical (some horizontal) | Horizontal (built-in) | Horizontal (built-in) |78| **Transactions** | Full ACID | Limited (document-level) | Varies by product | None (typically) | None (typically) |79| **Query language** | SQL | Vendor-specific (MQL, etc.) | Cypher, Gremlin, SPARQL | GET/SET commands | InfluxQL, Flux, SQL |80| **Joins** | Excellent | Poor (application-level) | Excellent (traversals) | None | Limited |8182**Decision heuristic:**83- Default to **relational** (PostgreSQL) when data is structured and relationships matter.84- Choose **document** when schema flexibility and developer velocity are priorities, and joins are rare.85- Choose **graph** when the primary queries traverse relationships (social networks, recommendations, fraud detection).86- Choose **key-value** for caching, sessions, and simple lookup-by-key workloads.87- Choose **time-series** for append-heavy, time-stamped data with downsampling and retention needs.88- Polyglot persistence is common: use the right database for each bounded context.8990## Backend Architecture Concerns9192### Rate Limiting & Throttling93Protect backend services from abuse and overload:94- **Token Bucket** -- allows bursts up to a configured capacity, refills at a steady rate.95- **Sliding Window** -- counts requests in a rolling time window for smoother limiting.96- **Fixed Window** -- simple counter per time window (risk of burst at window boundaries).97- **Leaky Bucket** -- processes requests at a constant rate, queuing excess.98- Implement at the API gateway layer for consistency across services.99100### Background Processing101Offload long-running or non-urgent work from the request/response cycle:102- **Job queues** (Sidekiq, Celery, Hangfire, BullMQ) -- enqueue work, process asynchronously.103- **Scheduled jobs** (cron, Quartz, Hangfire recurring) -- time-triggered processing.104- **Event-driven workers** -- react to domain events from a message broker.105- **Batch processing** -- periodic bulk operations (ETL, report generation).106- Always design for idempotency -- workers may process the same job more than once.107108### Observability109The three pillars of observability, plus health monitoring:110- **Logging** -- structured logs (JSON) with correlation IDs for request tracing.111- **Metrics** -- counters, gauges, histograms (request rate, error rate, latency percentiles).112- **Distributed Tracing** -- end-to-end trace across services (OpenTelemetry, Jaeger, Zipkin).113- **Health checks** -- liveness (is the process running?) and readiness (can it serve traffic?).114- **Alerting** -- thresholds on key metrics (error rate > 1%, p99 latency > 500ms).115116## Canonical Reference117- *Designing Data-Intensive Applications* by Martin Kleppmann -- the definitive guide to data storage, replication, partitioning, encoding, and distributed system trade-offs. Essential reading for any backend architect.118119## Sub-Skills120- `dev/backend/data-modeling` -- Data modeling and database architecture patterns121- `dev/backend/api-design` -- API design patterns for REST, GraphQL, gRPC, WebSocket122- `dev/backend/caching` -- Caching strategies and patterns123- `dev/backend/authentication` -- Authentication and authorization patterns124125## Best Practices126- Start with a monolith and extract services only when complexity demands it -- premature microservices add coordination cost without proportional benefit.127- Choose boring technology by default. PostgreSQL, Redis, and a well-designed REST API solve the vast majority of backend problems.128- Design for failure: every network call can fail, every database can be slow. Use timeouts, retries with backoff, circuit breakers, and fallbacks.129- Make operations idempotent wherever possible -- especially for writes, background jobs, and event handlers.130- Instrument everything from day one. Adding observability retroactively is far more expensive than building it in.131- Treat API contracts as public commitments: version explicitly, deprecate gracefully, never break existing clients without a migration path.