Last year we audited the infrastructure of a client's product — a SaaS with about 3,000 active users and a team of four engineers. They were paying $1,400/month for Datadog. When we asked what dashboards they looked at regularly, the answer was: none. They'd set it up because "you're supposed to have observability," built a few dashboards during the initial excitement, and then never looked at them again. The alerts fired so frequently they'd been muted.
This is the observability trap for small teams. The tools designed for companies with hundreds of services and dedicated SRE teams get adopted by teams of five, and the result is expensive noise. You don't need less observability — you need the right observability, scoped to what a small team can actually act on.
§ 01The observability trap for small teams
Enterprise observability platforms — Datadog, New Relic, Splunk — are built for organizations with complex distributed systems and dedicated operations teams. They're powerful. They're also designed around assumptions that don't hold for small teams:
- They assume someone is watching dashboards during business hours. Small teams don't have that person.
- They assume the system has dozens of services with complex interdependencies. Small products usually have one to three services.
- They assume the team has time to build and maintain custom dashboards. Small teams don't.
- They assume a monthly bill of $1,000-10,000 is acceptable. For a startup burning runway, it's not.
The result is a tool that's simultaneously too powerful and too noisy. The team sets it up, gets overwhelmed by the data, and falls back to the debugging method they used before: reading logs in the terminal and asking "what changed recently?"
The best observability stack for a small team is the one that gets looked at when something breaks, not the one with the most features.
§ 02Structured logging — the foundation
Everything starts with structured logging. Not console.log("user signed up") — structured JSON logs with consistent fields that can be searched, filtered, and aggregated.
The minimum fields on every log line:
// Every log line, every service { "timestamp": "2026-01-14T09:23:41.123Z", "level": "info", "message": "Order created", "service": "api", "requestId": "req_abc123", "userId": "usr_def456", "duration": 142, "metadata": { "orderId": "ord_ghi789", "total": 129.99 } }
The requestId field is critical. Every incoming request gets a unique ID, and that ID is attached to every log line generated during the request lifecycle. When something goes wrong, you search by request ID and get the complete story of what happened, in order, across every function that touched the request.
We use pino in Node.js applications. It's the fastest structured logger available, it outputs JSON by default, and it integrates cleanly with most hosting platforms. In development, we pipe through pino-pretty for readable output. In production, the raw JSON goes to whatever log aggregation service the client uses.
For log aggregation, we default to the platform's built-in solution: Vercel's log drain, Railway's log viewer, or AWS CloudWatch. These aren't as powerful as dedicated log platforms, but they're free (or nearly free) and they're sufficient for a team that needs to search logs when debugging, not build dashboards from them.
§ 03Error tracking that actually gets looked at
Error tracking is the one piece of observability that every team, regardless of size, must get right. When a user hits an error in production, you need to know about it before they email you, and you need enough context to fix it without asking them to reproduce it.
We use Sentry on every project. Not because it's the only option — there's Bugsnag, Highlight, LogRocket — but because Sentry's free tier is generous enough for most small products, the SDK integration is a one-liner, and the error grouping is good enough to avoid the "1,000 identical errors" problem that makes teams mute their alerts.
The setup that works:
- Install the SDK. One line in your application entry point. Sentry captures unhandled exceptions and rejections automatically.
- Set up source maps. Without source maps, Sentry shows you minified stack traces that are useless. With source maps, you see the exact file and line number. This takes five minutes to configure and is worth every second.
- Configure alerts for new errors only. Sentry can alert on every error occurrence. Don't do this — you'll mute the channel within a week. Instead, alert when a new error (one Sentry hasn't seen before) appears. This means your Slack channel only fires when something genuinely new breaks, not when the same known bug triggers for the 500th time.
- Attach user context. When a user is authenticated, set their ID and email on the Sentry scope. When an error fires, you know who was affected, and you can proactively reach out before they report it.
Alert on new errors, not all errors. Otherwise you'll mute the channel within a week.
— Ops setup guide, alert rules
§ 04Uptime and performance monitoring
You need to know two things: is the service up, and is it fast enough? For a small team, these don't require a full APM (Application Performance Monitoring) solution. They require two simple checks:
Uptime monitoring: A service that hits your health endpoint every 60 seconds and alerts you if it fails. We use BetterStack (formerly Better Uptime) or UptimeRobot. The setup takes five minutes: enter the URL, configure the check interval, connect it to Slack or PagerDuty. Done. If the site goes down at 3 AM, you get a phone call. If it's up, you hear nothing.
Performance monitoring: Core Web Vitals measured from real user data, not synthetic tests. Vercel Analytics provides this for free if you're on Vercel. If you're not, the web-vitals library sends real user metrics to any endpoint you choose. We send them to a simple API route that logs them as structured JSON. Once a week, someone scans the logs for LCP or INP regressions. That's the entire performance monitoring process.
What we skip: distributed tracing, custom metrics dashboards, percentile breakdowns by region, and anything that requires configuring a time-series database. These are valuable at scale. For a team of five with one to three services, they're overhead that produces data nobody looks at.
§ 05When you DON'T need Datadog
You don't need Datadog (or New Relic, or Splunk) when:
- Your application is a monolith or has fewer than five services.
- Your team has fewer than ten engineers.
- You don't have a dedicated person who looks at dashboards daily.
- Your monthly infrastructure budget is under $5,000.
- Your debugging process starts with "check the logs and recent deploys."
You need a full observability platform when:
- You have more than ten services and requests traverse multiple of them.
- You have a dedicated SRE or platform team.
- You need to correlate events across services to understand failures.
- Your compliance requirements mandate detailed audit trails and retention.
Most products we work on fall squarely in the first category. They need visibility, not an observability platform. There's a meaningful difference.
§ 06The stack we ship to every client
# Minimal observability stack Logging: pino (structured JSON) → platform log drain Errors: Sentry (free tier, new-error alerts only) Uptime: BetterStack (60s checks, phone alerts) Performance: web-vitals → structured log endpoint Alerting: Slack channel (#alerts) with three rules: 1. Site down → phone call 2. New Sentry error → Slack 3. Deploy succeeded/failed → Slack Cost: $0-20/month
That's the entire stack. It takes about two hours to set up on a new project. It catches the things that actually break production for a small team: the service going down, new errors appearing, and performance regressions. It doesn't catch everything. It doesn't need to. It catches enough that you can sleep at night and fix issues before your users report them.
The principle behind all of this is simple: observe what you'll act on. If a metric fires and your response is "huh, interesting" instead of "I need to fix this," remove the metric. Every alert that doesn't result in action trains the team to ignore alerts, and an ignored alerting system is worse than no alerting system at all.
Start with structured logs, Sentry, and an uptime check. Add more when you have a specific problem that requires more data. Not before.
— End of essay. Want us to set up your observability stack? Start a project →