There’s a moment every developer hits where things technically work… but you still don’t trust anything.
For me, that moment came when I moved our deployment system to the cloud.
As part of the project, we were building a platform where a user could upload a project, automatically build a Docker image, run it as a container, and get a live URL.
On paper, everything worked.
The VM was up.
The service was running.
Nothing had crashed.
And yet…
I had no idea if my system was actually working.
The Only Way I Could Check
At that point, I had built just one endpoint:
POST /upload
This endpoint did everything:
- Accept a zipped project
- Build a Docker image
- Run a container
- Expose a port
- Return a URL
So if I wanted to check whether my system was alive…
I had to deploy something.
Upload → Build → Run → Pray
That’s when it hit me:
I had built a system where the only way to check if it was alive… was to deploy an app.
Why I Added a /health Endpoint
I stopped and asked a simple question:
Why do I need a full deployment pipeline just to check if my service is alive?
I didn’t need builds.
I didn’t need containers.
I didn’t need logs.
I just needed a way to ask:
“Hey… are you alive?”
So I added:
GET /health
And that tiny decision changed how I think about systems.
What is a Health Route?
A health route is a lightweight HTTP endpoint that tells whether your application is functioning correctly.
GET /health
Response:
{
"status": "healthy"
}
That’s it.
- No business logic
- No side effects
- No heavy computation
Just a signal.
This endpoint isn’t for users.
It’s for systems, controllers, proxies, deployment pipelines, anything that needs to decide:
“Can I trust this service right now?”
Why This Matters: Running ≠ Working
Before this, I assumed:
Container started → App is ready
But that’s not true.
A container can be “running” while:
- the app is still initializing
- the database isn’t connected
- dependencies are failing
- something is internally broken
Without a health check, your platform is guessing.
With a health check, your platform knows.
That difference is what separates a toy system from a reliable one.
What Happens During Deployment
When an app starts, it doesn’t become ready instantly. It goes through a sequence:
- Container starts
- Application boots
- Dependencies initialize
- Database connects
- Server starts listening
- Finally ready
Without health checks, most systems assume:
Container started → Ready
Which leads to users hitting an app that isn’t ready yet.
With a Health Check
Instead of guessing, the system becomes smarter:
Now only ready applications receive traffic.
This makes deployments far more stable.
Liveness vs Readiness (The Real Upgrade)
Once you start thinking about health properly, you realize one endpoint isn’t enough.
There are actually two different questions:
Liveness → “Are you alive?”
- Checks if the app process is still running
- If this fails → restart the container
/health/live
Readiness → “Are you ready?”
- Checks if the app can handle real traffic
- If this fails → don’t send traffic (but don’t kill it)
/health/ready
Simple Analogy
- Liveness = Student is in class
- Readiness = Student studied for the exam
Just because something is running…
doesn’t mean it’s ready.
The Smallest Fix That Made a Big Difference
After all the confusion and overengineering, the actual solution was just a few lines of code.
Here’s how it looks in Go, but the idea is the same in any backend.
package main
import (
"encoding/json"
"net/http"
"time"
)
var startTime = time.Now()
type HealthResponse struct {
Status string `json:"status"`
Uptime float64 `json:"uptime_seconds"`
}
func HealthHandler(w http.ResponseWriter, r *http.Request) {
response := HealthResponse{
Status: "healthy",
Uptime: time.Since(startTime).Seconds(),
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(response)
}
func main() {
http.HandleFunc("/health", HealthHandler)
http.ListenAndServe(":8080", nil)
}
No orchestration.
No complexity.
Just a tiny endpoint that tells the truth.
What Changed After This
With this one route, I could:
- Instantly verify if my system is running
- Avoid unnecessary deployments just for testing
- Make my platform smarter about when to trust an app
It’s a small addition.
But it completely changes how your system behaves.
Best Practices (Quick Notes)
- Keep it lightweight → this endpoint is called frequently
-
Use proper status codes
-
200→ healthy -
503→ not ready
-
Separate liveness and readiness
Avoid over-checking dependencies
Always use timeouts (never let health checks hang)
Final Thought
The /health endpoint is probably the smallest route in your application.
But it might also be the most important one.
Because it answers the one question your entire system depends on:
“Can I trust this service right now?”

Top comments (0)