Cloud & Serverless: how to choose the right architecture (without going “too serverless”).
Cloud ≠ Serverless. Cloud is about infrastructure as managed services; Serverless is about events and managed runtimes. The best systems are usually hybrid: your API lives in containers, while “spiky” and heavy workloads run in serverless + queues.
1) Why everyone talks about Cloud and Serverless
Modern products are rarely just “a website + a database”. They typically include:
- files (uploads, PDFs, images, video),
- background work (emails, notifications, sync, analytics),
- integrations (CRM, payments, webhooks),
- traffic spikes (ads, launches, seasonality).
The classic “one server does everything” setup starts to hurt:
- the API gets blocked by long-running operations,
- scaling becomes painful,
- deployments get risky,
- infrastructure becomes “handcrafted art”.
Cloud gives you managed building blocks.
Serverless removes part of the ops burden and encourages an event-driven approach.
2) Cloud vs Serverless — what it actually means Cloud (in practice)
A set of managed services:
- DB (Postgres as a service),
- Storage (S3),
- Queue (SQS/Redis),
- Email (SES),
- CDN (CloudFront),
- Observability (logs/traces/metrics).
You build from managed components, but you still own:
- architecture,
- security,
- data modeling,
- deployments,
- SLOs/monitoring.
Serverless (in practice)
“Code that runs on events”:
- request/queue/cron/event,
- automatic scaling,
- pay-per-execution,
- less ops overhead.
But there are trade-offs:
- cold starts,
- time/memory limits,
- harder debugging,
- a different design style (event-driven).
3) The most common mistakes with Serverless ❌ 1) Making everything serverless
Serverless is great for:
- file processing (resize/compress),
- webhook ingestion,
- scheduled tasks,
- async jobs,
- event-driven pipelines.
But “put everything into Lambda” often leads to:
- fragmented code,
- versioning chaos,
- painful local development,
- unpredictable latency.
❌ 2) No queues and no retries
Background workflows without a queue = random failures and manual restarts.
Queues aren’t optional — they’re control + insurance.
❌ 3) A “fat API”
If the API generates PDFs, processes images, and calls 5 integrations in-line — it becomes a slow monolith.
4) Architectural options: 3 production-proven patterns (with analysis)
Below are three patterns that work well in real systems.
Pattern A: Railway-first MVP (fast, simple, affordable)
When to use: MVPs, startups, fast releases, small teams.
Stack:
- Railway API (Fastify)
- Railway Postgres (Prisma)
- Railway Worker (Node job runner)
- Redis + BullMQ for jobs
- AWS S3 for files
- AWS SES for email
Flow:
- API writes to Postgres
- API enqueues a job in Redis/BullMQ
- Worker executes: email, PDF, integrations
- Uploads go directly to S3 via presigned URLs
Pros:
- extremely fast to ship
- minimal infrastructure overhead
- great developer experience
- API stays responsive
Cons:
- Redis/BullMQ is fine for MVP, but at very large scale it may require extra care
- “enterprise” features like DLQ and complex routing may push you toward SQS later
Pattern B: Event-driven backbone on AWS (SQS + Scheduler)
When to use: stable traffic, growing async logic, need retries and control.
Stack:
- Railway API (Fastify)
- Railway Postgres (Prisma)
- AWS SQS (queue)
- AWS EventBridge Scheduler (cron)
- Railway Worker (poll SQS)
- AWS S3, SES
- (optional) AWS Lambda for file pipelines
Flow:
- API writes to Postgres
- API publishes a message to SQS (event type + payload)
- Worker consumes SQS, executes, retries, logs
- Scheduler triggers recurring jobs by publishing to SQS
Pros:
- reliability: retries, DLQ, strong control
- clear event model
- easy to add integrations
- scheduler runs “like clockwork”
Cons:
- more services → more discipline
- you must think about idempotency
Pattern C: Hybrid “API in containers + serverless for spikes”
When to use: lots of media/files, uneven traffic, many integrations/webhooks.
Stack:
- API: Railway (Fastify)
- DB: Railway Postgres
- Storage: S3 (+ CloudFront)
- Lambda: image/pdf processing, webhook ingestion
- SQS: async tasks
- Worker: longer tasks or specific integrations
File flow:
- client → presigned → S3
- S3 event → Lambda → processed assets
- metadata → DB
Pros:
- perfect for spikes and media pipelines
- cost-efficient when idle
- fast event-driven processing
Cons:
- you need good observability practices
- event-driven pipelines are harder to test
5) A recommended architecture for your stack (Fastify + Prisma + Postgres, AWS + Railway)
Here’s a “best of both worlds” approach: MVP-friendly, with a clean path to scale.
MVP baseline
- Railway: api, worker, postgres
- Redis/BullMQ for jobs
- AWS S3 + SES
Scaling path
- migrate jobs from Redis → AWS SQS
- add EventBridge Scheduler
- move file pipelines to Lambda
This gives you:
- fast delivery
- planned scalability
- no need to rewrite core
6) Practical principles that save you in production ✅ 1) Keep the API fast
API: validate → write DB → enqueue → respond.
Everything else runs in workers/serverless.
✅ 2) Idempotency everywhere
Events can be delivered twice.
Solutions:
- store jobId in DB
- use unique constraints
- “already processed” guards
✅ 3) Don’t add observability after launch
Minimum:
- requestId correlation
- structured logs
- error tracking (Sentry)
- metrics for queue depth / failures
✅ 4) Use presigned URLs for uploads
Don’t proxy file uploads through the API — it’s a costly bottleneck.
7) Conclusions: how to choose your Serverless path Choose PaaS-first (platform-first) if:
- MVP / fast releases matter more than a perfect cloud-native setup
- small team and you don’t want to spend weeks on DevOps
- you want a simple dev flow: deploys, logs, env vars, previews — “out of the box”
- your core needs are API + database + a couple of background workers/crons
Idea: start on any managed platform and avoid premature complexity.
Railway is only an example here — same idea applies to Render/Fly.io/Heroku, etc.
Choose Event-driven (cloud-native) serverless if:
- you have lots of async work (queues, event processing, integrations)
- you need retries, DLQ, execution control, delivery guarantees
- integrations are growing and a “simple worker” stops being enough
- you need scalability and isolation around events
Choose Hybrid if:
- you deal with media/files/pipelines (upload → processing → delivery)
- traffic is spiky and you want to pay per usage, not for an always-on server
- you want the simplicity of one API plus the power of queues/functions
- you plan to move heavy tasks to serverless gradually, without a big refactor
Choose Railway-first if:
- you’re shipping an MVP
- small team, fast iterations
- you want a simple dev flow
Choose AWS event-driven if:
- you have lots of async workloads
- you need retries/DLQ/control
- integrations keep growing
Choose Hybrid if:
- media/files/pipelines are core
- traffic is spiky
- you want automatic scaling and cost efficiency
ITway Author
Tech Enthusiast & Writer