DEV Community

Cover image for Cutting My Self-Hosted Analytics Stack Memory by 45%
Sivaram
Sivaram

Posted on

Cutting My Self-Hosted Analytics Stack Memory by 45%

260MB for a personal analytics dashboard. Just tracking 4,000 events across 21 websites over 5 days. Barely any data, but my Bun server was eating 150MB and TimescaleDB was claiming 120MB like it was serving a production SaaS.

On Railway's usage-based $5 plan, every MB counts. Time to optimize.

The Stack

  • Server: Bun + Hono + Drizzle ORM + Better-Auth
  • Database: TimescaleDB (PostgreSQL for time-series data)
  • Cache: Redis
  • Frontend + Proxy: Nginx serving Vite/React SPA with reverse proxy to backend

Server Optimizations (150MB → 50-60MB)

  1. Removed unused OpenAPI/Zod schema introspection - heavy libs not needed for single-user project
  2. Used Bun's --smol flag - smaller memory footprint GC with more aggressive garbage collection. Minimal perf impact for low-traffic apps. This one's a hidden gem.
  3. Removed --sourcemap and --bytecode - unnecessary overhead in production binaries

TimescaleDB Optimizations (100-120MB → 60-80MB)

The TimescaleDB defaults were completely overkill for a personal project:

Setting Default Optimized What it does
shared_buffers 1907MB 128MB Memory for caching table/index data. Default was set to 25% of RAM - insane for a personal project
maintenance_work_mem 953MB 64MB Memory for VACUUM, CREATE INDEX, etc. Almost 1GB for maintenance ops!
work_mem 2.4MB 4MB Memory per query operation (sorts, joins). This was already reasonable
max_background_workers 16 8 Workers for chunk compression/maintenance. Halved but still plenty
telemetry_level basic off Disables TimescaleDB telemetry. Saves CPU cycles and network calls
-- Memory settings (tuned down for single-user workload)
ALTER SYSTEM SET shared_buffers = '128MB';
ALTER SYSTEM SET maintenance_work_mem = '64MB';
ALTER SYSTEM SET work_mem = '4MB';

-- TimescaleDB settings
ALTER SYSTEM SET timescaledb.max_background_workers = '8';
ALTER SYSTEM SET timescaledb.telemetry_level = 'off';

SELECT pg_reload_conf();
Enter fullscreen mode Exit fullscreen mode

Results

Component Before After Reduction
Bun Server 150MB 55MB -63%
TimescaleDB 110MB 70MB -36%
Redis 8MB 8MB Already lean
Nginx + Frontend 35MB 35MB Already lean
Total ~300MB ~170MB -45%

From a memory-hungry pet project to something a Raspberry Pi could handle without breaking a sweat.

Key Takeaway

Don't assume defaults are right for your use case. A personal project doesn't need the same configuration as a high-traffic SaaS. Right-size your infrastructure - that 130MB headroom means I can spin up another test project or two without bumping tiers.

Top comments (0)