Z
Zoe
Guest
What I Used to Think
When I first started working with Kubernetes, I took the textbook advice at face value: "Always split your readiness and liveness probes." It made sense:
- Readiness: tells the load balancer when your app is ready to serve traffic
- Liveness: tells Kubernetes when your app is stuck or dead and should be restarted
So naturally, I assumed they always had to be different.
Spoiler: they don't.
What I Actually Learned
If your app is a frontend app with no external dependencies (no DB, no Redis, nothing fancy) then you can totally use the same endpoint for both liveness and readiness.
And that's okay.
Usually, you'll have some kind of /health or /ping endpoint that just returns 200 OK if the server is alive. That's enough.
Because in this case:
- There's nothing to warm up
- No connection pools to wait for
- No race conditions between booting and serving traffic
Just a server that says "I'm alive," and that's all you need.
TL;DR: If your frontend just needs to be "up", you don't need fancy health check logic.
When You Should Actually Separate Them
There are cases when you absolutely want them to be different. For example:
- Your app connects to a DB or other service and needs time to become "ready"
- Your app could freeze or hang over time and needs to be restarted
- You want different failure thresholds (e.g. retry readiness more often than liveness)
In those cases:
- Readiness: returns 200 only when all dependencies are ready
- Liveness: returns 200 unless the app is completely hung or stuck
Think of readiness as "Can I take requests?" and liveness as "Am I still breathing?"
Infra-Side Example: One Path, Two Probes
If you're working on a static frontend or a lightweight SSR app, this setup is totally fine:
Code:
readinessProbe:
httpGet:
path: /health/readiness
port: 3000
initialDelaySeconds: 3
periodSeconds: 10
livenessProbe:
httpGet:
path: /health/liveness/
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
App-Side Example
Code:
// Fastify or Express-style handler
app.get('/health/liveness/', (_, reply) => {
reply.code(200).send({ status: 'READY' })
})
app.get('/health/readiness/', (_, reply) => {
reply.code(200).send({ status: 'READY' })
})
No extra logic. No retries. No checks. Just a 200 if the app is alive.
Final Thoughts

If you're deploying a frontend-only app with no infra dependencies, a single /health endpoint is enough for both probes.
But as your app grows and gains more infra complexity (e.g. connecting to databases, caches, or async queues ) then it's time to revisit and split them accordingly.
Knowing when it matters is the real win.

Continue reading...