platformsh/config-reader
A PHP library for reading configuration from the Platform.sh environment. It parses platform relationships and variables into usable service credentials and environment settings, helping applications adapt cleanly across deployments and environments.
What the package is. platformsh/config-reader is a single-purpose, dependency-free PHP helper (namespace Platformsh\ConfigReader\Config) that decodes the base64-encoded JSON blobs Platform.sh injects into the runtime environment — PLATFORM_RELATIONSHIPS, PLATFORM_ROUTES, PLATFORM_APPLICATION, PLATFORM_PROJECT, PLATFORM_ENVIRONMENT — and exposes them through typed accessors (getRelationship(), getRoutes(), getPrimaryRoute(), getApplicationName(), isValidPlatform(), and DSN-formatting helpers for PDO/Redis). It does no caching, no validation beyond decode, and no framework integration.
Architecture fit. Good for what it is: a thin environment adapter, not a framework. In a Laravel codebase the correct placement is inside config/*.php files (or a single config/platform.php shim), so that service credentials are resolved once at bootstrap and then flow through Laravel's normal config pipeline. It is not a substitute for a service container binding, a connection factory, or a multi-cloud abstraction. TPM framing: treat it as a 200-line vendor shim, not as an architectural component.
Integration feasibility. High on Platform.sh/Upsun, effectively zero elsewhere. Concrete strengths:
env() parsing quirks — base64 payloads with +, /, = padding and embedded JSON are read via getenv()/$_ENV superglobals rather than Dotenv's value normalization. This is the main technical reason to prefer it over hand-rolled env('PLATFORM_RELATIONSHIPS').config/database.php stays readable.Technical risk.
null/empty rather than exceptions, so misconfiguration can degrade into a confusing "database connection refused" rather than a precise bootstrap error.php artisan config:cache has run, relationship values are frozen into the artifact. That is acceptable for immutable deploys but must be verified against the deploy lifecycle: if credentials rotate without a redeploy, the cached config is stale. This is the single highest-probability production incident vector.Key questions for the team.
platformsh/laravel-bridge) already cover our needs, making direct use of this package redundant?config:cache at build or at deploy, and are all PLATFORM_* values we consume actually populated at that phase?Stack fit. Laravel-native in mechanics, PaaS-specific in semantics. The reader should be confined to configuration resolution:
| Config file | Consumed relationship |
|---|---|
config/database.php |
database (mysql/postgres) → host, port, user, password, path |
config/cache.php / config/session.php |
redis |
config/queue.php |
rabbitmq or redis |
config/mail.php |
mail/SMTP relationship or API key via env |
config/filesystems.php |
object storage credentials |
config/broadcasting.php, search |
solr/elasticsearch |
Recommended shape. Do not scatter Config::getRelationship() calls across a dozen config files. Introduce one config/platform.php (or App\Support\PlatformRelationships) that:
null when Config::isValidPlatform() is false, so local/Docker/CI uses ordinary .env values;host, port, database, username, password);null into a fail-fast bootstrap error;platform.database.* etc., so application code never imports the vendor class directly.That single decision converts an unbounded lock-in surface into a one-file swap and makes the exit plan a day of work rather than a sprint.
Migration path (sequenced).
Compatibility considerations.
composer.json and commit composer.lock; low-traffic vendor packages do not warrant floating constraints.config:cache timing against the platform's build-vs-deploy environment variable availability; run one deliberate test in a preview environment rather than reasoning about it.Maintenance. Low ongoing cost — the package's surface area is small and stable, and releases are infrequent (latest 2025-02-25). The real maintenance burden is not the code but the wrapper and the deploy-time validation around it, which we own regardless of whether we adopt this package.
Support. Upstream support is effectively the platform vendor's documentation and issue tracker; there is no meaningful third-party community to lean on given the adoption numbers. For a TPM this argues for: pinning, a local fork or vcs mirror if the dependency is judged critical-path, and a named internal owner for the wrapper.
Scaling. Negligible runtime cost. All reads happen during bootstrap; there is no per-request overhead, no I/O, no external call. Scaling risk is entirely environmental (relationship limits, service plan sizing), not attributable to this package.
Failure modes to design against.
null → confusing downstream connection error. Mitigate with the fail-fast wrapper..env values structurally identical to the normalized relationship array.#[SensitiveParameter]-style convention in the wrapper.Ramp-up. Low. A mid-level Laravel engineer can read the whole package and wire the first service in an afternoon; the wrapper, guard, and fail-fast behaviour are a one-to-two-day task. Realistic rollout estimate: 2–4 engineering days for a typical Laravel app with database, Redis, and one additional backing service, plus half a day of preview-environment validation. No specialist platform knowledge is required beyond understanding how Platform.sh exposes relationships.
Recommendation. Adopt it — but only behind a single internal adapter, pinned, with fail-fast validation and a documented exit path. The package earns its place by solving one real problem (safe decoding of base64 relationship payloads) that hand-rolled env parsing gets wrong; it does not earn a place in application code, and the low adoption numbers make the wrapper mandatory rather than optional.
How can I help you explore Laravel packages today?