PGPM Module Naming: npm Names vs Control File Names
pgpm modules have two different identifiers that serve different purposes. Understanding when to use each is critical for correct dependency management.
When to Apply
Use this skill when:
-
Creating or editing .control files
-
Writing -- requires: statements in SQL deploy files
-
Running pgpm install commands
-
Referencing dependencies between modules
-
Publishing modules to npm
The Two Identifiers
Every pgpm module has two names:
- npm Package Name (for distribution)
Defined in package.json as the name field. Used for npm distribution and the pgpm install command.
Format: @scope/package-name (scoped) or package-name (unscoped)
Examples:
-
@sf-bot/rag-core
-
@san-francisco/sf-docs-embeddings
-
@pgpm/base32
- Control File Name / Extension Name (for PostgreSQL)
Defined by the .control filename and %project= in pgpm.plan . Used in PostgreSQL extension system and SQL dependency declarations.
Format: module-name (no scope, no @ symbol)
Examples:
-
rag-core
-
sf-docs-embeddings
-
pgpm-base32
When to Use Each
Use npm Package Name (@scope/name )
- pgpm install command:
pgpm install @sf-bot/rag-core @sf-bot/rag-functions @sf-bot/rag-indexes
- package.json dependencies:
{ "dependencies": { "@sf-bot/rag-core": "^0.0.3" } }
Use Control File Name (name )
- .control file requires line:
sf-docs-embeddings.control
requires = 'rag-core'
- SQL deploy file requires comments:
-- Deploy data/seed_collection to pg -- requires: rag-core
- pgpm.plan %project declaration:
%project=sf-docs-embeddings
- Cross-package references in pgpm.plan:
data/seed [rag-core:schemas/rag/schema] 2026-01-25T00:00:00Z Author <author@example.com>
Real-World Example
Consider the sf-docs-embeddings module:
package.json (npm name for distribution):
{ "name": "@san-francisco/sf-docs-embeddings", "version": "0.0.3" }
sf-docs-embeddings.control (control name for PostgreSQL):
sf-docs-embeddings extension
comment = 'San Francisco documentation embeddings' default_version = '0.0.1' requires = 'rag-core'
pgpm.plan (control name for project):
%project=sf-docs-embeddings
deploy/data/seed_collection.sql (control name in requires):
-- Deploy data/seed_collection to pg -- requires: rag-core
The Mapping
pgpm maintains an internal mapping between control names and npm names. When you run pgpm install , it:
-
Reads the .control file's requires list (control names)
-
Maps those to npm package names
-
Installs the npm packages
For example, if your .control has requires = 'pgpm-base32' , pgpm knows to install @pgpm/base32 from npm.
Common Mistakes
Wrong: Using npm name in .control file
WRONG
requires = '@sf-bot/rag-core'
CORRECT
requires = 'rag-core'
Wrong: Using control name in pgpm install
WRONG
pgpm install rag-core
CORRECT
pgpm install @sf-bot/rag-core
Wrong: Using npm name in SQL requires
-- WRONG -- requires: @sf-bot/rag-core
-- CORRECT -- requires: rag-core
Quick Reference Table
Context Use Example
pgpm install
npm name @sf-bot/rag-core
package.json name npm name @sf-bot/rag-core
package.json dependencies npm name @sf-bot/rag-core
.control requires control name rag-core
SQL -- requires:
control name rag-core
pgpm.plan %project control name rag-core
Cross-package deps control name rag-core:schemas/rag
Summary
-
npm names (@scope/name ): Used for distribution and installation via npm/pgpm install
-
Control names (name ): Used for PostgreSQL extension system, .control files, and SQL dependency declarations
Think of it this way: npm names are for the JavaScript/npm ecosystem, control names are for the PostgreSQL ecosystem.
References
-
Related skill: pgpm-cli for CLI commands
-
Related skill: pgpm-workspace for workspace structure
-
Related skill: pgpm-changes for authoring database changes