Tests should use NullPool (no shared connections) so each session is fresh and isolated. Production needs pool_size + pool_pre_ping + pool_recycle so dropped connections are detected before they break a request. Async engines also need echo=False in prod to keep logs readable.
test env: NullPool, echo=False. dev: small pool, echo=True. prod: pool_size=20, pool_pre_ping=True, pool_recycle=3600.
Alembic migration CLI uses a SEPARATE synchronous engine to avoid event-loop mishaps.
Lazy engine creation via engine_kwargs = {**defaults} and branching on settings.environment keeps one Settings class.
Settings.environment -> engine_kwargs:
test -> NullPool, echo=False
prod -> pool_size=20, pool_pre_ping=True, pool_recycle=3600
Different environments want different pools. Branch on Settings.environment, not on whether you feel lucky.