Previously: In Testing Your Database Module, we added tests to the pets module. Now let's explore multi-module dependencies.
The real power of pgpm workspaces emerges when you build multiple modules that depend on each other. Instead of manually tracking deployment order, pgpm resolves the entire dependency graph automatically. In this lesson, you'll create modules that depend on other modules, use cross-module references, and leverage recursive deployment.
Prerequisites
See Prerequisites. Requires: Complete Creating Your First Postgres Database Module.
Understanding Module Dependencies
Modules declare dependencies in their .control file. Dependencies can be:
- Native Postgres extensions (pgcrypto, citext, postgis)
- Other database modules in your workspace
When you deploy a module, pgpm automatically deploys all dependencies first.
Step 1: Create a Dependent Module
Let's create an adoptions module that depends on the pets module:
Enter the module name:
The module scaffolds with no dependencies. Now add pets as a dependency with pgpm extension --add:
pgpm discovers pets by scanning the workspace for .control files, and writes it to the requires line:
You could also declare it up front at init time with
pgpm init --extensions pets. Either way you end up with the same.control.
Step 2: Add Schema and Table Changes
Still inside the adoptions module, add a schema:
Edit deploy/schemas/adoptions.sql:
Add an adoptions table:
Edit deploy/schemas/adoptions/tables/adoptions.sql:
This table references pets.pets(id) from the pets module. pgpm ensures the pets module deploys first.
Step 3: Deploy with Recursive Resolution
Deploy the adoptions module:
pgpm automatically:
- Detects that
adoptionsdepends onpets - Checks if
petsis already deployed - Deploys
petsif needed (skipped if already deployed) - Deploys
adoptions
This is recursive deployment—pgpm resolves the entire dependency tree automatically.
Step 4: Cross-Module Change Dependencies
You can declare dependencies on specific changes from other modules. Add a change that depends on a specific change in the pets module:
Edit deploy/schemas/adoptions/tables/adoption_history.sql:
The -- requires: pets:schemas/pets/tables/pets comment tells pgpm this change depends on the schemas/pets/tables/pets change from the pets module.
Step 5: Understanding Dependency Resolution
pgpm resolves dependencies by:
- Scanning the workspace for all
.controlfiles - Building a dependency graph from
requiresfields - Resolving topological order (which modules deploy first)
- Deploying in sequence with transactional safety
Step 6: Managing Extension Dependencies
pgpm extension is the canonical way to change a module's dependencies after init. It edits only the requires line of the .control file, leaving every other field intact.
Non-interactive (scripts, CI):
Interactive picker:
Tip: Use spacebar to select/deselect, arrow keys to navigate, and Enter to confirm. pgpm updates the .control file automatically—only the requires line changes, so custom fields you've added (comment, schema, relocatable) are preserved.
Note: The
pgpm installcommand is for installing npm-based database packages (e.g.,@pgpm/base32) into your module's extensions/ directory. That's a different workflow covered in advanced lessons.
Key Takeaways
- Modules declare dependencies in
.controlfiles - pgpm automatically resolves dependency graphs
- Recursive deployment deploys all dependencies automatically
- Cross-module references use
module:changesyntax pgpm extension --add/--remove/--setmanages dependencies (or run it with no flags for an interactive picker)- pgpm detects circular dependencies
- Shortest path wins for naming collisions
Multi-module dependencies make pgpm workspaces powerful. Let's explore testing and packaging next.

