Constructive Workspaces: A New Way to Organize PostgreSQL Projects
Database development shouldn't feel like you're stuck in 2005. When you want to build a new feature, you shouldn't spend hours configuring migration tools, manually tracking dependencies, or wondering if your schema changes will deploy in the right order.
The Problem: Monolithic Database Development
Traditional database development treats your entire schema as one giant migration chain. You write SQL files, number them sequentially, and hope they run in order. When you want to reuse a schema across projects, you copy-paste SQL files and lose all version history. When modules depend on each other, you manually track what needs to deploy first.
This doesn't scale.
Frontend developers expect modularityβthey install packages with npm install, compose applications from reusable components, and let the package manager handle dependency resolution. Database development deserves the same sophistication.
Constructive Workspaces: npm for PostgreSQL
constructive workspaces bring npm-style modularity to PostgreSQL. Instead of monolithic migration scripts, you build focused modules that declare their dependencies explicitly. Instead of manual deployment orchestration, you get automatic dependency resolution.
A constructive workspace is a pnpm monorepo containing multiple database modules. Each module is self-contained with its own migrations, dependencies, and version tags. When you deploy, constructive discovers all modules, resolves the dependency graph, and deploys everything in the correct order.
Workspace
The top-level directory containing your entire project. It has a constructive.json configuration file and a packages/ directory where modules live.
Think of it like: Your npm project root with package.json
Module
A self-contained database package inside the workspace. Each module has its own constructive.plan file, .control file, and deploy/, revert/, verify/ directories.
Think of it like: An individual npm package
Example Workspace Structure
my-workspace/ # Workspace root βββ constructive.json # Workspace config βββ packages/ # Modules directory β βββ users/ # Module: user management β β βββ constructive.plan β β βββ users.control β β βββ deploy/ β β βββ revert/ β β βββ verify/ β βββ organizations/ # Module: org management β βββ constructive.plan β βββ organizations.control β βββ deploy/ β βββ revert/ β βββ verify/
How Modules Declare Dependencies
Modules declare dependencies in their .control file, similar to package.json:
# organizations.control comment = 'Organization management module' default_version = '0.0.1' requires = 'users,uuid-ossp'
This tells constructive that the organizations module depends on the users module and the uuid-ossp PostgreSQL extension. When you deploy organizations, constructive automatically deploys users first.
Automatic Dependency Resolution
When you run constructive deploy, constructive:
- 1Scans your workspace for all modules (by finding .control files)
- 2Builds a dependency graph from the requires fields
- 3Resolves the topological order (which modules must deploy first)
- 4Deploys modules in the correct sequence
- 5Tracks what's been deployed in the constructive_migrate schema
You never manually specify deployment order. constructive handles the orchestration automatically.
Cross-Module References
Modules can reference changes from other modules in their dependency declarations. If your organizations module needs a specific change from the users module, you can declare it:
-- Deploy tables/memberships -- requires: users:tables/users CREATE TABLE organizations.memberships ( user_id UUID REFERENCES users(id), organization_id UUID REFERENCES organizations(id) );
The -- requires: users:tables/users comment tells constructive that this change depends on the tables/users change from the users module. constructive ensures users:tables/users deploys before this change.
Composability
Build reusable modules that work across projects
Explicit Dependencies
Dependencies are declared in code, not documentation
Transactional Safety
All deployments happen in transactions with automatic rollback
Fast Iteration
TypeScript-based engine deploys complex schemas in milliseconds
Cross-Project Reuse
Publish modules to npm and install them with constructive install
Zero Config
No build tools, no manual migration management needed
The Future of Database Development
The future of database development is modular, composable, and fast. constructive workspaces bring the best practices from frontend development to PostgreSQLβgiving you the tools to build databases the way you build applications.
Ready to get started?
Stay in the loop
Follow our journey. Watch us build. Be the first to know.
Building in public. Open source from day one.