How I Built an Uber-like API for Lithuanian Taxi Provider Without Breaking the Bank

TL;DR: I replaced expensive third-party routing and geocoding APIs with a self-hosted stack using OSRM for routing and Nominatim for geocoding. Running on a single €15/month Hetzner ARM instance, this solution reduced potential mapping costs from hundreds of euros monthly to predictable VPS bills—while maintaining production-level performance for my Lithuania-focused ride-hailing service with 50 drivers.

P.S. This project launched in 2014 and is still running strong today.

The Problem: When Success Becomes Expensive

Building a ride-hailing service seems straightforward until you realize how quickly mapping costs can spiral. Every "find nearest driver" request can generate dozens of API calls if implemented carelessly. For a small geography like Lithuania with a modest fleet of 50 drivers, I needed a solution that wouldn't bankrupt the business as it grew.

Paid routing and geocoding services are undeniably convenient, but their usage scales linearly with every trip and driver matching operation. I faced a classic startup dilemma: the more successful the service became, the more expensive it would be to operate.

Why I Ditched Google Maps APIs

After running the numbers, three key factors drove my decision to self-host:

Predictable costs over pay-per-use billing. No more surprises when order volume spikes during peak hours or bad weather.

Complete control over performance. I could optimize caching, set my own rate limits, and control data freshness without vendor restrictions.

Freedom from vendor lock-in. Using OpenStreetMap data meant no licensing headaches and the ability to customize mapping logic for local needs.

The Data Foundation

The beauty of focusing on Lithuania is the manageable data scale. I use OpenStreetMap data via Geofabrik's country extract:

  • Lithuania OSM file: ~150MB currently (started at under 80MB in 2014)
  • OSRM preprocessing: Completes in minutes on a modest VPS
  • Nominatim import: Takes longer but remains feasible for country-level data

This geographic focus transforms what could be a massive infrastructure challenge into something surprisingly manageable.

Driver Matching: Three Approaches to Consider

Finding the nearest available driver isn't as simple as it sounds. Here are three implementation strategies, each with distinct trade-offs:

1. The Naive Approach: Route to Everyone

Calculate routing duration to every candidate driver (50 drivers = 50 individual API calls per request).

  • Pros: Most accurate ETA for each driver
  • Cons: Expensive API usage, unacceptable latency at scale

2. The Optimized Approach (My Choice)

Step A: Filter drivers using Haversine distance to select ~10 nearest candidates by straight-line distance
Step B: Use a single OSRM matrix request to compute actual driving durations

  • Pros: Nearly identical accuracy with 80% fewer API calls
  • Cons: Requires matrix endpoint support and efficient batching logic

3. Precomputed Spatial Indexing

Maintain geohash/S2 spatial indexes with precomputed travel-time buckets for dense areas.

  • Pros: Lightning-fast queries with minimal API usage
  • Cons: Complex implementation, potential staleness with moving drivers

I chose approach #2 because it delivers the optimal balance of accuracy, cost, and implementation complexity for my scale.

The Real Cost Breakdown

Let me show you the actual numbers based on current Google Maps Platform pricing (August 2025):

Google Maps API Pricing

  • Distance Matrix: $5.00 per 1,000 elements (first 100k), then $4.00 per 1,000
  • Geocoding: $5.00 per 1,000 requests (first 100k), then $4.00 per 1,000
  • Routes API: $5.00 per 1,000 requests (Essentials tier)

Note: Each API includes 10,000 free monthly requests

My Usage Pattern

  • Fleet size: 50 drivers
  • Matrix elements per order: 10 (rider to 10 nearest drivers after Haversine filtering)
  • Geocoding per order: 2 requests (pickup + destination addresses)

Cost Comparison by Volume

1,000 orders/month:

  • Google Maps: $0 (within free tier)
  • Self-hosted: €15/month
  • Winner: Google (for now)

5,000 orders/month:

  • Google Maps: ~€180/month
  • Self-hosted: €15/month
  • Savings: €165/month

15,000 orders/month:

  • Google Maps: ~€690/month
  • Self-hosted: €15/month
  • Savings: €675/month

The naive approach penalty: If I had used 50 route calls per order instead of 10, costs at 5,000 monthly orders would exceed €1,000 just for routing.

Break-Even Analysis

  • Break-even point: ~1,200 orders/month
  • Sweet spot: 5,000+ orders where savings become substantial
  • Scale advantage: Costs remain flat regardless of volume spikes

Production Performance Reality Check

After nearly a decade in production, here's what actually matters:

Latency: OSRM responds in 50-200ms for routing queries. Nominatim geocoding typically takes 100-400ms for Lithuanian addresses.

Reliability: Running on the same VPC eliminates external API dependencies and network variability.

Scaling options: Horizontal scaling with load balancing or vertical scaling with larger instances. OSRM's MLD mode leverages multi-core systems effectively — perfect for my 8-core ARM instance.

Data freshness: Monthly OSM updates during low-traffic windows. OSRM reprocessing is fast; Nominatim requires more patience but remains manageable.

Infrastructure: Keep It Simple

Current setup:

  • Single Hetzner ARM instance (8 vCPU, 16GB RAM): €15/month
  • Docker Compose orchestration
  • Monthly OSM data updates

Total monthly cost: €15 regardless of order volume

Lessons Learned the Hard Way

  1. Always use matrix endpoints instead of individual route calls—this single optimization can reduce API costs by 80%
  2. Implement Haversine pre-filtering to avoid wasting matrix elements on obviously distant drivers
  3. Cache geocoding results aggressively for 30+ days where licensing permits
  4. Schedule OSM updates carefully during low-traffic periods
  5. Understand ODbL licensing if you plan to redistribute or share OSM-derived data

Is Self-Hosting Right for You?

Self-hosting mapping services makes sense if you:

  • Have predictable geographic focus (country or region)
  • Process 1,200+ orders monthly
  • Value cost predictability over convenience
  • Can invest initial setup time for long-term savings
  • Want complete control over performance and caching

It's not ideal if you:

  • Need global coverage from day one
  • Operate below break-even volume
  • Lack technical resources for maintenance
  • Require specialized routing (wheelchair accessibility, real-time traffic)

The Bottom Line

For geographically-focused ride-hailing applications, self-hosting OSRM and Nominatim delivers production-grade mapping services at a fraction of vendor costs. Smart matching algorithms that minimize unnecessary API calls are essential regardless of your chosen approach.

After nearly a decade running this setup, replacing expensive mapping APIs with self-hosted alternatives remains one of my best technical infrastructure decisions. The combination of predictable costs, improved control, and solid performance has enabled sustainable growth without the anxiety of escalating third-party bills.

Cost savings at scale: From €690/month with Google Maps to €15/month self-hosted at 15,000 orders — that's money better invested in drivers, marketing, or product development.