Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Postgres Schema Bundle Laravel Package

macpaw/postgres-schema-bundle

Symfony bundle for PostgreSQL schema-based multi-tenancy. Switch the active database schema per request or tenant, integrate with Doctrine, and isolate data without managing separate databases. Includes schema-aware connection and listener support.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

The package is named macpaw/postgres-schema-bundle and packaged as a Symfony bundle, not a Laravel package. That distinction remains the single most important finding for a TPM sizing this work: Laravel has no bundle lifecycle. There is no Bundle class, no DI Extension, no compiler passes, and no bundle registration in config/app.php or bootstrap/providers.php. Whatever value exists in the repo has to be re-hosted inside a Laravel service provider before it can be evaluated at all. The v2.0.8 patch release does not change this.

The reusable surface is likely narrow but real: Postgres schema DDL logic, search_path management, and console commands (Laravel already runs on Symfony Console, so command classes are largely portable). The non-portable surface is the Symfony wiring, config loading (YAML/XML rather than Laravel's config/*.php array style), and any Doctrine DBAL coupling. Laravel's relationship to Doctrine is transactional only — doctrine/dbal is pulled in for specific schema-introspection paths, not as a data-access layer — so a bundle that assumes Doctrine connections, Doctrine migrations, or Doctrine event subscribers will need an adapter layer rather than a shim.

Net: poor packaging fit, moderate logic fit. Treat this as "a library of Postgres schema operations you may be able to extract," not "a package you install."

Integration feasibility

Feasible, but it is a build project, not an adoption project. A realistic path is: (1) stand the bundle up in a throwaway Symfony skeleton to learn the actual API surface and confirm what it does; (2) extract the framework-agnostic core; (3) write a Laravel provider, config file, and command wrappers; (4) wire search_path into Laravel's connection resolver and reset hooks. Estimate 2–4 engineer-weeks to production-ready, most of it in steps 3–4 and in testing the tenant-isolation boundary.

v2.0.8 is relevant to step 4 specifically: it fixes schema state not being reset on transaction rollback, which is one of the state-lifecycle edges that a Laravel port would otherwise have to discover and patch itself. That is a small but genuine de-risking of the port — it is evidence the maintainers are actively working the hard part (session-state correctness across lifecycle boundaries) rather than only packaging.

Before committing, this must be compared against build-vs-buy alternatives. The capability domain — Postgres schema-per-tenant management — is well served by stancl/tenancy and spatie/laravel-multitenancy, both of which are Laravel-native, have real adoption, and already solve the Octane/queue-worker search_path leak problem. A TPM should require an explicit written justification for choosing a zero-adoption third-party core over either a maintained package or ~2 weeks of in-house DDL code.

Technical risk

Still high, concentrated in adoption signals rather than code quality, but the picture has shifted slightly on maintainer intent:

  • Zero stars, zero dependents. Still effectively an unvetted single-vendor publish. There is no community triage and no third-party production usage to learn from.
  • Maintainer intent: partially clarified, in a positive direction. v2.0.8 is a targeted correctness fix merged via a reviewed PR (#23) from a named maintainer (@alekseytupichenkov), with a versioned tag and a compare link. That is a working PR-and-release workflow, not a dead drop. It answers key question #6 in part: there is a reachable human, and the repo is being maintained. It does not answer whether MacPaw is using it internally or whether external issues get triaged.
  • Release metadata now partly corroborated. We can see v2.0.7 → v2.0.8 as a real, tagged increment with an attributable change. The prior assessment flagged the last-release date as unverifiable; that concern is reduced but not eliminated — one patch release is a single data point, not a track record. Verify CI status and test coverage directly before the spike.
  • The fix itself is a signal about the risk profile. That rollback-state handling was wrong in v2.0.7 tells you the state machine has real edge cases; that it was found and fixed tells you they are being worked. Both facts argue for the spike, not against it — but they also confirm that isolation correctness is exactly where the time will go.
  • Doctrine/DBAL version conflict risk. Unchanged. If the bundle pins DBAL 3.x and the target Laravel version has moved to 4.x (or vice versa), Composer resolution becomes the first blocker.
  • Tenant-isolation failure is a security incident, not a bug. search_path is session state. Any place where it can leak across requests — Octane workers, queued jobs, connection pools, and (per this release) rollback paths — is a cross-tenant data-exposure path. v2.0.8 closes one such path upstream; it does not close the ones the Laravel port would introduce.

Key questions

  1. What does the bundle actually do — schema-per-tenant provisioning, DDL diffing/migration, search_path routing, or all three? The description ("Postgres schema bundle") does not say. Still open.
  2. Is the core logic framework-agnostic, or does it call Symfony DI/EventDispatcher/Doctrine directly from the domain classes? Still open.
  3. What are the PHP, Symfony, and DBAL version constraints, and do they resolve cleanly alongside the target Laravel version? Still open; highest-priority pre-spike check.
  4. Does it own migrations, or delegate to an external migrator? If it owns them, is there transactional DDL and a rollback story? Partially answered — v2.0.8 shows explicit rollback handling exists and is being corrected, which implies it participates in transaction lifecycle rather than ignoring it.
  5. Is there a test suite and CI, and does it cover concurrent/multi-connection search_path behavior? A regression that shipped in v2.0.7 and was fixed in v2.0.8 suggests lifecycle-edge coverage was incomplete at least once. Verify current coverage; specifically ask whether the rollback scenario now has a regression test.
  6. Is there a named maintainer we can reach, and is MacPaw still using this internally? Half answered — yes to a named, active maintainer; internal-usage question unresolved.
  7. Is there any path to upstreaming a Laravel adapter, or is this permanently a fork? An active PR workflow modestly improves the odds, but no evidence a framework-agnostic core split is planned.

Integration Approach

Stack fit

The underlying technology is a good fit for the target stack — Postgres 13+ with schema-per-tenant is a legitimate, well-understood multi-tenancy model, and Laravel runs on Symfony Console so command classes survive the port. The friction is entirely at the packaging and data-access layers: Symfony DI config, Doctrine assumptions, and YAML configuration do not map onto Laravel idioms. Assume roughly 20% of the codebase is reusable as-is, 50% is portable with an adapter, and 30% (Symfony wiring) is discarded.

Migration path

Sequence the work so the go/no-go decision lands before any Laravel-specific investment:

  1. Sandbox spike (3–5 days). Symfony skeleton, install the bundle at v2.0.8, provision two schemas, run whatever commands it ships, and explicitly exercise the rollback path the patch touches. Goal: a one-page factual description of behavior, plus a verdict on whether the core is separable.
  2. Build-vs-buy decision gate. Compare the spike output against stancl/tenancy and a ~300-line in-house DDL implementation. Only proceed to step 3 if the bundle does something materially difficult that the alternatives do not.
  3. Extraction and adapter. Vendor-fork at a pinned tag (not a floating branch) with an explicit UPSTREAM.md, extract the domain layer, write PostgresSchemaServiceProvider, publishable config array, and command wrappers. Carry the v2.0.8 rollback fix through any refactor — it is a correctness fix, not cosmetic.
  4. Connection integration. Hook search_path into ConnectionEstablished/ConnectionResolved and, critically, into Octane request lifecycle, queue worker job boundaries, and transaction rollback / exception unwind paths — the last being the class of bug v2.0.8 just fixed upstream. Assume the Laravel port will reintroduce that bug unless it is tested for.
  5. Rollout behind a flag on staging with synthetic tenants, then a single low-risk production tenant before general availability.

Compatibility

Pin and verify against a specific Laravel minor before the spike, not after. Validate three things in parallel: DBAL constraint resolution, PHP constraint resolution against the runtime image, and whether the bundle's config schema can express what the target environment needs (schema naming, tenant identifier validation, connection-per-tenant vs search_path switching). Treat the fork as an internal package with its own version line — do not depend on upstream tags for production stability, even though upstream tagging is now demonstrably functional.

Sequencing

The dependency chain is strict: spike → decision gate → adapter → isolation testing → staged rollout. Isolation testing (step 4) must be a hard gate, not a parallel track, because everything downstream assumes it passed. Budget the majority of engineering time there rather than in the porting work, which is comparatively mechanical. Add one explicit test this cycle: mid-transaction rollback with an active tenant, asserting search_path returns to the expected state — this is a direct regression test against the v2.0.7 defect and costs hours, not days.

Operational Impact

Maintenance

You will own this permanently in practice, but the cost estimate improves marginally. v2.0.8 demonstrates an active, reviewable release process with attributable commits, which reduces — but does not eliminate — the "abandoned experiment" scenario. Zero dependents still means upstream will not triage your issues, and there is no changelog discipline beyond the auto-generated compare link. Budget ongoing fork maintenance — rebasing, DBAL constraint updates, Postgres major-version compatibility — as a standing line item, roughly a few days per quarter. The upside of an active upstream is that some correctness work (like this rollback fix) arrives for free if you stay close to upstream; the downside is that each upstream release is a rebase you must validate, since you have no contributor stake in it.

Support

MIT, no vendor, no SLA, no security advisory channel. Security patching is entirely internal, and there is no CVE feed to watch. Mitigate by keeping the fork small and well-tested, documenting the exact behavioral contract the application depends on, and assigning a named internal owner. The risk here is not that the code is bad — it is that nobody outside the team will ever tell you it is. A named upstream maintainer is a courtesy channel, not a support contract; do not plan around it.

Scaling

Schema-per-tenant scales well to hundreds of schemas and poorly to tens of thousands: Postgres catalog performance degrades as pg_catalog grows, autovacuum works per-table across all schemas, and migrations become fan-out operations that must be chunked and made resumable. Connection handling is the sharper edge — with PgBouncer in transaction mode, session-level search_path is not reliably scoped and the safe configuration is per-tenant credentials or per-tenant databases rather than SET search_path. Establish the expected tenant ceiling and connection-pool topology before the adapter work, because those choices change the design.

Failure modes

Rank by severity, not likelihood:

  • search_path leakage across requests or jobs → cross-tenant data exposure. Highest severity, highest likelihood in an Octane or queue-heavy deployment. Mitigate with explicit set-and-reset around every unit of work and an automated test that asserts isolation under concurrent load.
  • search_path not reset on transaction rollback or exception unwind → subsequent statements in the same session execute against the wrong schema. Severity is equivalent to the above; the defect class was live upstream through v2.0.7 and is fixed in v2.0.8. This is now the highest-value thing to verify in the spike and the highest-value test to carry into the fork.
  • Unvalidated tenant identifier interpolated into DDL or SET → schema injection. Validate against a strict allowlist pattern before any identifier reaches SQL; identifiers cannot be parameterized.
  • Partial DDL failure leaving a schema half-provisioned → orphaned tenants with no clean teardown. Require transactional DDL and an idempotent provisioning command.
  • Schema drift as application migrations and schema-level operations diverge.
  • Dependency resolution breakage on the next Laravel or DBAL upgrade, discovered late because the fork has no CI.

Ramp-up

Moderate. The porting engineer needs genuine fluency in both Symfony DI and Laravel's container and lifecycle hooks — an uncommon combination, and a poor fit for a generalist PHP developer. Expect two to three weeks before that person is productive on this specific task, plus the isolation-testing effort. On the positive side, the conceptual model (Postgres schemas as tenant boundaries) is simple and well documented elsewhere; almost none of the ramp-up cost is domain learning.

TPM recommendation

The score (14.4) with zero stars and zero dependents, packaged for a framework the target stack does not use, remains a do-not-adopt as a dependency signal. The opportunity score (46.9) is defensible — multi-tenant Postgres schema management is genuinely valuable — but the value lives in the capability, not in this artifact.

v2.0.8 does not change the verdict, but it improves two inputs and should be reflected in the decision record: there is a named, active maintainer with a functioning PR/release workflow, and one of the top-ranked failure modes (state reset on rollback) has been actively worked upstream. Recommended action: fund the 5-day spike against a pinned v2.0.8, and add two acceptance criteria to it — reproduce the rollback scenario and confirm the fix, and inspect whether a regression test accompanies it. If both hold, the "extract the core" path becomes more credible; if the spike shows the core is inseparable from Symfony/Doctrine wiring, fall back to stancl/tenancy or in-house DDL and cite this bundle as design reference only.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package