{"id":166,"library":"neon","title":"Neon (Serverless PostgreSQL)","description":"Neon is a serverless PostgreSQL platform (acquired by Databricks May 2025 for ~$1B). Not a Python package — connect using standard PostgreSQL drivers (psycopg2, psycopg, asyncpg, SQLAlchemy). Two connection string types: pooled (-pooler in hostname, via PgBouncer) and direct. Pooled is now the default in Neon Console. Critical: always include sslmode=require. asyncpg with pooled connections requires statement_cache_size=0.","status":"active","version":"platform","language":"python","source_language":"en","source_url":"https://neon.com/docs/connect/choose-connection","tags":["neon","postgresql","serverless","pgbouncer","asyncpg","psycopg2","python"],"install":[{"cmd":"pip install psycopg2-binary","lang":"bash","label":"Python (sync — development)"},{"cmd":"pip install psycopg","lang":"bash","label":"Python (sync/async — psycopg v3)"},{"cmd":"pip install asyncpg","lang":"bash","label":"Python (async)"}],"dependencies":[],"imports":[{"note":"Always include sslmode=require in Neon connection strings. Omitting it raises: 'SSL connection has been closed unexpectedly' or connection refused.","wrong":"import psycopg2\n# Missing sslmode — raises SSL connection required error\nconn = psycopg2.connect('postgresql://user:pass@ep-xxx.neon.tech/dbname')","symbol":"psycopg2 connection","correct":"import psycopg2\nimport os\n\n# Pooled connection (default from Neon Console)\n# hostname includes -pooler\nconn = psycopg2.connect(\n    os.environ['DATABASE_URL']  # must include sslmode=require\n)\n# DATABASE_URL format:\n# postgresql://user:pass@ep-xxx-pooler.region.aws.neon.tech/dbname?sslmode=require"},{"note":"Neon pooler uses PgBouncer in transaction mode. asyncpg's prepared statement cache breaks with PgBouncer transaction mode. Always set statement_cache_size=0 when using the pooled connection string.","wrong":"import asyncpg\n\n# Using pooled URL without statement_cache_size=0\npool = await asyncpg.create_pool(os.environ['DATABASE_URL'])\n# Raises: prepared statement 'asyncpg_stmt_X' does not exist","symbol":"asyncpg with Neon pooler","correct":"import asyncpg\nimport os\n\nasync def get_pool():\n    # Neon pooler uses PgBouncer in transaction mode\n    # Must disable prepared statement cache\n    pool = await asyncpg.create_pool(\n        os.environ['DATABASE_URL'],\n        statement_cache_size=0  # required for Neon pooler\n    )\n    return pool"},{"note":"Use DIRECT (non-pooler) connection string for schema migrations. PgBouncer transaction mode breaks migration tools. Neon Console provides both — pooled has -pooler in hostname.","wrong":"# Using pooled URL for Alembic migrations\n# Raises: prepared statement errors or transaction issues\nalembic.ini: sqlalchemy.url = postgresql://...pooler.../neondb?sslmode=require","symbol":"direct vs pooled URL","correct":"# Pooled — for app traffic (up to 10k concurrent connections)\nDATABASE_URL = 'postgresql://user:pass@ep-cool-rain-123456-pooler.us-east-2.aws.neon.tech/neondb?sslmode=require'\n\n# Direct — for migrations only (alembic, django migrate)\nDATABASE_URL_UNPOOLED = 'postgresql://user:pass@ep-cool-rain-123456.us-east-2.aws.neon.tech/neondb?sslmode=require'"}],"quickstart":{"code":"# pip install psycopg2-binary python-dotenv\nimport psycopg2\nfrom dotenv import load_dotenv\nimport os\n\nload_dotenv()\n\n# Use pooled URL from Neon Console (includes -pooler in hostname)\nconn = psycopg2.connect(os.environ['DATABASE_URL'])\n# DATABASE_URL=postgresql://user:pass@ep-xxx-pooler.region.aws.neon.tech/neondb?sslmode=require\n\ncur = conn.cursor()\ncur.execute('SELECT version()')\nprint(cur.fetchone())\n\ncur.execute(\n    'SELECT * FROM users WHERE id = %s',\n    (1,)\n)\nrows = cur.fetchall()\n\ncur.close()\nconn.close()","lang":"python","description":"Minimal Neon PostgreSQL connection with psycopg2."},"warnings":[{"fix":"Always append ?sslmode=require to connection strings. Neon Console copies include it automatically.","message":"sslmode=require is mandatory for Neon connections. Omitting it causes SSL errors or connection refusal. Neon enforces TLS.","severity":"breaking","affected_versions":"all"},{"fix":"await asyncpg.create_pool(dsn, statement_cache_size=0)","message":"asyncpg with Neon pooler (PgBouncer transaction mode) raises 'prepared statement asyncpg_stmt_X does not exist'. Breaks under any concurrent load.","severity":"breaking","affected_versions":"all"},{"fix":"Set DATABASE_URL_UNPOOLED (no -pooler in hostname) for migration commands. Use DATABASE_URL (pooler) for app traffic.","message":"Schema migrations (Alembic, Django migrate, Prisma Migrate) must use the DIRECT connection string, not the pooled one. PgBouncer transaction mode breaks migration session state.","severity":"breaking","affected_versions":"all"},{"fix":"Use pooled connection string for web apps. Consider Neon's 'always-on' setting for latency-sensitive workloads.","message":"Neon computes scale to zero after inactivity. First connection after idle period has 300-500ms cold start latency. Using the pooler (PgBouncer) mitigates this — PgBouncer maintains warm connections.","severity":"gotcha","affected_versions":"all"},{"fix":"Check your connection string hostname. Pooled: ep-xxx-pooler.region.aws.neon.tech. Direct: ep-xxx.region.aws.neon.tech.","message":"Pooled connection strings are now the default in Neon Console (since Jan 2025). If you copied a connection string before Jan 2025 it may be a direct connection without -pooler.","severity":"gotcha","affected_versions":"all"},{"fix":"engine = create_async_engine(DATABASE_URL, connect_args={'statement_cache_size': 0})","message":"SQLAlchemy with asyncpg on Neon pooler requires statement_cache_size=0 in connect_args: create_async_engine(url, connect_args={'statement_cache_size': 0})","severity":"gotcha","affected_versions":"all"},{"fix":"Ensure 'python-dotenv' is listed in your project's dependencies (e.g., requirements.txt or pyproject.toml) and is properly installed. You can install it manually using `pip install python-dotenv`.","message":"The 'ModuleNotFoundError: No module named 'dotenv'' indicates that the 'python-dotenv' package, required for loading environment variables from a .env file, is not installed in the execution environment.","severity":"breaking","affected_versions":"all"},{"fix":"Ensure `python-dotenv` is listed in your project's `requirements.txt` or equivalent dependency management file, and that dependencies are installed correctly (e.g., `pip install python-dotenv`).","message":"The `dotenv` package is required by the application but was not found. This typically means the package was not included in the project's dependencies or failed to install.","severity":"breaking","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T09:12:34.922Z","next_check":"2026-06-24T00:00:00.000Z","problems":[{"fix":"Upgrade your PostgreSQL client library to version 14 or higher (which supports SNI), or explicitly pass the endpoint ID as a parameter in the connection string, for example, '&options=endpoint%3D[endpoint_id]' or by specifying it in the password field as 'endpoint=[endpoint_id];[password]'.","cause":"This error occurs when an older PostgreSQL client library (libpq) or application does not support the Server Name Indication (SNI) mechanism in TLS, which Neon uses to route incoming connections based on compute IDs.","error":"ERROR: The endpoint ID is not specified."},{"fix":"Verify that the username, password, and database name in your connection string are correct. Ensure that `sslmode=require` (or `sslmode=verify-full` for stronger security) is explicitly included in your connection string.","cause":"This is a general PostgreSQL authentication error, which in Neon often arises from incorrect database credentials (username, password, or database name) or by not including `sslmode=require` in the connection string, as Neon requires all connections to use SSL/TLS encryption.","error":"FATAL: password authentication failed for user \"your_user\""},{"fix":"For SQLAlchemy, upgrade to version 2.0.33 or later, set `pool_recycle` to a value less than or equal to your Neon compute's scale-to-zero setting, and enable `pool_pre_ping=True` to ensure connections are alive before use. Alternatively, avoid pooled connections for long-lived applications by using `NullPool` with external pooling.","cause":"This error, often seen as `SSL SYSCALL error: EOF detected`, typically occurs when an application tries to reuse a database connection after the Neon compute instance has scaled down to zero due to inactivity, causing the connection to become stale.","error":"SSL connection has been closed unexpectedly"},{"fix":"Disable `asyncpg`'s prepared statement cache by setting `statement_cache_size=0` when creating the `asyncpg` connection pool. If using SQLAlchemy with asyncpg, also ensure `prepared_statement_name_func` is set to generate unique names for statements.","cause":"This error occurs when using `asyncpg` with Neon's pooled connections (which use PgBouncer in transaction mode), because PgBouncer in this mode does not properly support PostgreSQL's prepared statements that `asyncpg` might attempt to use.","error":"asyncpg.exceptions.InvalidSQLStatementNameError: unnamed prepared statement does not exist HINT: NOTE: pgbouncer with pool_mode set to \"transaction\" or \"statement\" does not support prepared statements properly."}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.4,"disk_size":"77.4M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.4,"disk_size":"152M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2.1,"disk_size":"83.7M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":2.1,"disk_size":"158M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":2.1,"disk_size":"74.2M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":2.1,"disk_size":"149M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":2.1,"disk_size":"70.7M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":1.9,"disk_size":"147M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.2,"disk_size":"76.6M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":2.2,"disk_size":"151M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}