k6 is one of the most popular open-source load testing tools used by developers and SREs to stress-test APIs, services, and web applications. But load testing and uptime monitoring serve different purposes — and using them together gives you a complete picture of your application's reliability.
In this tutorial you'll learn how to set up continuous uptime monitoring with Vigilmon for the services you load test with k6, so you catch both performance regressions during tests and real-world outages between test runs.
Load testing vs. uptime monitoring
These are complementary, not competing, tools:
| Tool | When it runs | What it tells you | |------|-------------|-------------------| | k6 | On-demand or in CI | How your app behaves under synthetic traffic spikes | | Vigilmon | 24/7 continuously | Whether your app is reachable from the real internet right now |
k6 tells you whether your /api/orders endpoint can handle 500 concurrent users. Vigilmon tells you whether /api/orders has been returning 500 errors for the last 3 minutes while you slept. You need both.
What you'll need
- k6 installed locally or in CI
- A service to load test (any HTTP API or web app)
- A free Vigilmon account — sign up in under a minute, no credit card required
Step 1: Add a health endpoint to your service
Before load testing, add a /health route to your application. This gives Vigilmon a lightweight, dependency-verified endpoint to poll continuously — and gives k6 a quick sanity check at the start of every test run.
Node.js / Express:
app.get('/health', async (req, res) => {
try {
// Optionally check your DB connection
await db.query('SELECT 1');
res.json({ status: 'ok', timestamp: new Date().toISOString() });
} catch (err) {
res.status(503).json({ status: 'error', message: err.message });
}
});
Python / FastAPI:
@app.get("/health")
async def health():
return {"status": "ok", "timestamp": datetime.utcnow().isoformat()}
Go / Gin:
r.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
Make sure the endpoint returns HTTP 200 when healthy and a non-200 status code (503 is conventional) when degraded.
Step 2: Write a k6 load test
Here's a typical k6 script that tests your API under increasing load. Save it as load-test.js:
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate } from 'k6/metrics';
const errorRate = new Rate('errors');
export const options = {
stages: [
{ duration: '2m', target: 50 }, // ramp up to 50 virtual users
{ duration: '5m', target: 50 }, // hold at 50 VUs
{ duration: '2m', target: 200 }, // spike to 200 VUs
{ duration: '5m', target: 200 }, // hold at 200 VUs
{ duration: '2m', target: 0 }, // ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95th percentile under 500ms
errors: ['rate<0.01'], // less than 1% errors
},
};
const BASE_URL = __ENV.TARGET_URL || 'https://your-api.example.com';
export default function () {
// Health check
const health = http.get(`${BASE_URL}/health`);
check(health, {
'health is 200': (r) => r.status === 200,
});
// Core API endpoints
const res = http.get(`${BASE_URL}/api/products`, {
headers: { Authorization: `Bearer ${__ENV.API_TOKEN}` },
});
const success = check(res, {
'status is 200': (r) => r.status === 200,
'response time < 200ms': (r) => r.timings.duration < 200,
});
errorRate.add(!success);
sleep(1);
}
Run the test:
TARGET_URL=https://your-api.example.com k6 run load-test.js
k6 outputs a summary at the end showing percentile latencies, error rates, and whether your thresholds passed. But during the 16-minute test, what's happening to your service from the perspective of real users? That's where Vigilmon comes in.
Step 3: Set up Vigilmon monitors for your tested services
- Log in to vigilmon.online and navigate to Monitors → New Monitor
- Choose HTTP / HTTPS
- Set the URL to your health endpoint:
https://your-api.example.com/health - Set check interval to 1 minute
- Under Expected response, set status code
200and optionally body contains"status":"ok" - Save the monitor
Add a second monitor for your main API endpoint:
- New Monitor → HTTP / HTTPS
- URL:
https://your-api.example.com/api/products - Check interval: 1 minute
- Expected status: 200
- Save
Vigilmon probes these endpoints every minute from multiple locations. If your service goes down — during a load test, during a deploy, or at 3am on a Sunday — you'll know immediately.
Step 4: Run k6 in CI and watch Vigilmon for incidents
When you run k6 in a CI/CD pipeline, it's valuable to correlate the test timeline with your Vigilmon monitor state. If k6 shows a spike in error rates at the same time Vigilmon fires an incident, you know the service actually became unavailable — not just slow.
Here's a GitHub Actions workflow that runs k6 and fails the build on threshold violations:
name: Load Test
on:
push:
branches: [main]
schedule:
- cron: '0 2 * * *' # daily at 2am
jobs:
load-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install k6
run: |
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg \
--keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] \
https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6
- name: Run load test
env:
TARGET_URL: ${{ secrets.STAGING_URL }}
API_TOKEN: ${{ secrets.API_TOKEN }}
run: k6 run load-test.js
- name: Check Vigilmon monitor status
run: |
# Optional: query Vigilmon API to verify no incidents during test window
echo "Check vigilmon.online for incident history"
Step 5: Configure Vigilmon alerts for real-time notification
During and after load tests you want immediate notification if something degrades. Set up alert channels in Vigilmon:
Slack alerts:
- Go to Alert Channels → Add Channel → Webhook
- Enter your Slack incoming webhook URL
- Assign the channel to both your monitors
Email alerts:
- Go to Alert Channels → Add Channel → Email
- Enter your on-call email address
- Enable for both monitors
When a monitor fires, Vigilmon sends:
{
"monitor_name": "API Health",
"status": "down",
"url": "https://your-api.example.com/health",
"started_at": "2024-07-01T14:23:00Z",
"duration_seconds": 120
}
This lets you correlate: "k6 ramped to 200 VUs at 14:21, Vigilmon fired at 14:23 — the app collapsed under load."
Step 6: TCP port monitoring for your load test targets
If your service exposes non-HTTP endpoints (Redis, PostgreSQL, gRPC), add TCP port monitors in Vigilmon:
- Monitors → New Monitor → TCP Port
- Enter your server hostname and port (e.g.
your-server.example.com/6379) - Save
Now you'll detect if the Redis cache that backs your API becomes unreachable mid-test.
Step 7: Create a status page for your tested services
If your API is customer-facing, a status page gives users and stakeholders visibility into uptime:
- Status Pages → New Status Page
- Name it (e.g. "API Status")
- Add your monitors
- Publish
Share the URL in your README.md or your developer portal. When k6 reveals a capacity issue that causes an outage, users can check the status page instead of flooding your support queue.
Putting it all together: load testing + monitoring workflow
Here's the complete workflow:
1. Deploy new version to staging
2. Vigilmon confirms /health returns 200 (pre-test sanity check)
3. k6 runs the load test: ramp up → spike → ramp down
4. Vigilmon monitors the endpoint throughout
5. If Vigilmon fires an incident during k6's ramp, you know the load threshold that breaks the service
6. k6 test finishes; check thresholds passed
7. Vigilmon continues monitoring in production 24/7
8. Next k6 run in 24h for regression detection
This means your team always has:
- k6: synthetic load data on demand, with CI enforcement
- Vigilmon: real-time availability data, 24/7, from external vantage points
Common patterns with k6 + Vigilmon
Smoke test + monitoring: Run a minimal k6 smoke test (1 VU, 1 minute) in CI just to verify the deploy didn't break anything, while Vigilmon provides continuous coverage between deployments.
Soak testing: Run k6 for 4-8 hours at moderate load. Vigilmon's 1-minute checks will catch memory leaks that cause the service to degrade gradually — before your soak test's error threshold triggers.
Breaking point testing: Ramp k6 to 1000+ VUs. Watch when Vigilmon fires its first incident. That's your breaking point.
What's next
- Set up k6 Cloud or Grafana k6 for distributed load generation from multiple regions — then correlate with Vigilmon's multi-region uptime data
- Add heartbeat monitors in Vigilmon if your k6 tests run on a schedule — Vigilmon will alert you if a test job stops running
- Enable SSL certificate monitoring in Vigilmon for all your test target domains
Get started free at vigilmon.online — monitors go live in under a minute, no credit card required.