Skip to content
Latchkey

SQLAlchemy "Can't load plugin: sqlalchemy.dialects:postgres" in CI

SQLAlchemy 1.4+ removed the postgres dialect alias; only postgresql is valid. A DATABASE_URL starting postgres:// (common from hosted providers) now fails to load a dialect.

What this error means

Engine creation fails with "sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres" when the URL scheme is postgres://.

python
sqlalchemy.exc.NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:postgres

Common causes

The URL uses the removed postgres:// scheme

A provider-supplied DATABASE_URL begins postgres://, an alias SQLAlchemy dropped in 1.4. Only postgresql:// resolves now.

An old URL survived a SQLAlchemy upgrade

Code that ran on SQLAlchemy 1.3 worked with postgres://; after upgrading, the same URL no longer loads a dialect.

How to fix it

Normalize the scheme to postgresql

Rewrite the scheme before building the engine so a provider URL works unchanged.

python
url = os.environ["DATABASE_URL"]
if url.startswith("postgres://"):
    url = url.replace("postgres://", "postgresql://", 1)
engine = create_engine(url)

Pick an explicit driver

Use a full scheme that names the driver so the dialect is unambiguous.

.github/workflows/ci.yml
# postgresql+psycopg2:// or postgresql+psycopg://
DATABASE_URL=postgresql+psycopg2://user:pass@127.0.0.1:5432/app

How to prevent it

  • Always use postgresql:// (or postgresql+driver://) in SQLAlchemy URLs.
  • Normalize provider URLs that ship the legacy postgres:// scheme.
  • Re-check connection URLs after a SQLAlchemy major upgrade.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →