ADR-005: Unified Package Design (trigger + binding → azure-functions-db)¶
Status¶
Accepted (2026-04-08)
Context¶
In the initial design, a package named azure-functions-dbtrigger was planned to provide only
DB change detection (trigger) functionality.
During development, the following requirements emerged:
- Providing DB reads (input binding) and writes (output binding) together improves user experience
- Splitting trigger and binding into separate packages forces users to install multiple packages
- A single package (
azure-functions-db) simplifies installation and configuration
Decision¶
Rename azure-functions-dbtrigger to azure-functions-db and include both
trigger (change detection) and binding (read/write) in a single package.
Internal Structure¶
core/: shared infrastructure (EngineProvider, DbConfig, types, errors, serializers)trigger/: existing polling trigger design, preserved as-isbinding/: DbReader (input), DbWriter (output)- Dependency direction: trigger→core, binding→core; cross-imports between trigger↔binding are prohibited
API Strategy¶
- Imperative API (DbReader, DbWriter) is primary
- Decorator API (
DbBindingswithtrigger,input,output) provides Azure Functions-native DX - Packages are unified; programming models are not
Alternatives Considered¶
Alternative A: Keep trigger-only (azure-functions-dbtrigger)¶
- Pros: focused scope, clear naming
- Cons: users who need binding must implement it themselves or install a separate package
- Rejected: poor user DX
Alternative B: Separate packages (azure-functions-dbtrigger + azure-functions-dbbinding)¶
- Pros: clear separation of concerns
- Cons: requires installing two packages; engine/config duplication
- Rejected: "having to download multiple packages is inconvenient"
Alternative C: Immediate unified API design (decorator-centric)¶
- Pros: clean, single API surface
- Cons: risk of decorator conflicting with Azure Functions runtime; locks in API before validation
- Rejected: safer to add decorators after the imperative API stabilizes
Rationale¶
- Technical synergy: natural sharing of engine/config/pool
- User convenience: a single
pip install azure-functions-dbcovers all DB operations - Scope management: internal core/trigger/binding separation isolates complexity
- Incremental delivery: trigger implemented first; binding added in Phase 8+
- Design review: adopted recommendation of "one package, but not one programming model"
Market Research¶
- Microsoft Azure Functions SQL Extension: SQL Server only, integrated trigger+binding extension
- Python-native package with equivalent scope: does not currently exist
- Our differentiators: multi-DB + Python-first + SQLAlchemy + single package
Consequences¶
- Package name:
azure-functions-db - Import:
azure_functions_db - Existing trigger design is preserved as-is
- Binding semantics defined in a separate document (22-binding-semantics.md)
- Development phasing: trigger (Phase 1–7) → shared core (Phase 8) → binding (Phase 9–11)