From Neon to Supabase to Aiven: A PostgreSQL Migration Odyssey

The Problem: Neon's 50-Hour Weekly Limit

Our scalable chat platform was initially deployed with Neon PostgreSQL as the database provider. Everything worked perfectly... until it didn't.

The Issue: Neon's free tier has a 50-hour weekly compute quota. Once exhausted, the database simply goes offline, taking our entire application down with it.

[ERROR] Connection refused: Database compute time exceeded weekly limit [ERROR] Service unavailable: Chat platform offline

This wasn't sustainable for a production application. Time to migrate.

Migration Journey: Three Providers, One Solution

Phase 1: The Supabase Attempt πŸ”΄

Target: Migrate from Neon to Supabase PostgreSQL
Outcome: Failed due to connectivity issues

Supabase seemed like the logical choice - generous free tier, PostgreSQL compatibility, and great developer experience. But reality had other plans.

The Technical Roadblocks

# Connection attempts failed consistently Connection to supabase.co:5432 refused Network unreachable from Render servers Timeout after 30s connection attempt

Root Causes Identified:

  • Network Connectivity: Render servers couldn't establish stable connections to Supabase
  • Authentication Errors: JWT token issues with connection pooling
  • Connection Pool Conflicts: HikariCP configuration incompatible with Supabase's pooler
  • AutoCommit Configuration: Transaction handling mismatches

Failed Configuration Attempts

# Multiple failed connection string variations jdbc:postgresql://db.supabase.co:5432/postgres?user=postgres.xyz&password=*** jdbc:postgresql://aws-0-us-west-1.pooler.supabase.com:5432/postgres jdbc:postgresql://db.xyz.supabase.co:6543/postgres?pgbouncer=true

Every variation resulted in timeouts or connection refused errors.

Phase 2: The Aiven Success Story 🟒

Target: Migrate from failed Supabase to Aiven PostgreSQL
Outcome: Complete success with optimized configuration

After Supabase failed, we discovered Aiven - a managed cloud database service with excellent PostgreSQL offerings.

Why Aiven Worked

  1. Stable Network Connectivity: Direct connection from Render to Aiven
  2. Optimized for Cloud Deployments: Built for container orchestration
  3. Generous Free Tier: 1-month trial with production features
  4. Excellent Documentation: Clear migration guides and best practices

The Technical Implementation

Database Schema Migration

# Export from Neon pg_dump $NEON_DATABASE_URL > neon_backup.sql  # Clean and optimize for Aiven sed -i 's/OWNER TO neondb_owner/OWNER TO avnadmin/g' neon_backup.sql  # Import to Aiven psql $AIVEN_DATABASE_URL < neon_backup.sql

Application Configuration Optimization

The key to success was optimizing HikariCP for cloud deployment:

# Critical configuration changes spring.datasource.hikari.auto-commit=false spring.datasource.hikari.connection-timeout=60000 spring.datasource.hikari.validation-timeout=30000 spring.datasource.hikari.max-lifetime=1800000 spring.datasource.hikari.maximum-pool-size=2 spring.datasource.hikari.minimum-idle=0

JDBC URL Optimization

// Optimized connection string for cloud deployment jdbc:postgresql://chat-platform-jeffrey-defaultdb.h.aivencloud.com:25578/defaultdb   ?sslmode=require   &autoCommit=false   &connectTimeout=60   &socketTimeout=60   &loginTimeout=60

Connection Pool Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚   Render Instance   β”‚    β”‚   Aiven PostgreSQL  β”‚    β”‚   Connection Pool   β”‚ β”‚                     β”‚    β”‚                     β”‚    β”‚                     β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚  Spring Boot    β”‚ │───▢│ β”‚  PostgreSQL 15  β”‚ │◄───│ β”‚  HikariCP       β”‚ β”‚ β”‚ β”‚  Application    β”‚ β”‚    β”‚ β”‚  Database       β”‚ β”‚    β”‚ β”‚  Max Pool: 2    β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚    β”‚ β”‚  Min Idle: 0    β”‚ β”‚ β”‚                     β”‚    β”‚                     β”‚    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚    β”‚                     β”‚ β”‚ β”‚  WebSocket      β”‚ β”‚    β”‚ β”‚  SSL/TLS        β”‚ β”‚    β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚  Connections    β”‚ β”‚    β”‚ β”‚  Encryption     β”‚ β”‚    β”‚ β”‚  Health Checks  β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚    β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚    β”‚ β”‚  SELECT 1       β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Performance Optimizations Applied

1. Timeout Configuration

# Increased timeouts for cloud latency connection-timeout=60000ms validation-timeout=30000ms socket-timeout=60000ms

2. Pool Size Optimization

# Conservative pool sizing for free tier maximum-pool-size=2 minimum-idle=0 max-lifetime=30min

3. Connection Validation

# Proactive connection testing connection-test-query=SELECT 1 test-while-idle=true test-on-borrow=true

4. AutoCommit Handling

# Multiple levels of autoCommit control hikari.auto-commit=false jdbc.url=...&autoCommit=false transaction.auto-commit=false

Migration Results

Before (Neon)

  • ❌ 50-hour weekly limit
  • ❌ Frequent downtime
  • ❌ Unpredictable availability
  • βœ… Fast performance when available

Failed Attempt (Supabase)

  • ❌ Network connectivity issues
  • ❌ Connection pool conflicts
  • ❌ Authentication problems
  • ❌ Unable to establish stable connection

After (Aiven)

  • βœ… Stable 24/7 availability
  • βœ… No usage time limits
  • βœ… Optimized cloud connectivity
  • βœ… Production-ready configuration
  • βœ… Excellent performance

Key Lessons Learned

1. Cloud Database Connectivity Varies

Not all PostgreSQL providers work equally well with all hosting platforms. Render + Aiven proved to be a winning combination where Render + Supabase failed.

2. Connection Pool Configuration is Critical

// The magic configuration that made it work spring.datasource.hikari.maximum-pool-size=2 spring.datasource.hikari.minimum-idle=0 spring.datasource.hikari.auto-commit=false

3. Multiple Timeout Layers Required

Cloud deployments need timeouts at every level:

  • JDBC driver timeouts
  • Connection pool timeouts
  • Application-level timeouts
  • Network stack timeouts

4. Migration Strategy Importance

Always have a rollback plan and test connectivity before full migration.

Current Architecture

Production Stack: β”œβ”€β”€ Frontend: React + TypeScript (Vercel) β”œβ”€β”€ Backend: Spring Boot (Render) β”œβ”€β”€ Database: PostgreSQL (Aiven) β”œβ”€β”€ Cache: Redis (Upstash) └── Storage: MongoDB Atlas

The application is now running stably on Aiven PostgreSQL with a robust, cloud-optimized database configuration. No more unexpected downtime due to quota limits.

Resources


Sometimes the third time's the charm. From Neon's limitations to Supabase's connectivity issues to Aiven's success - each failed attempt taught us valuable lessons about cloud database deployment.