fastd/config
Lightweight configuration component for FastD PHP applications: load and merge PHP config files, resolve environment-specific values and variables, access settings through a simple repository API, and cache parsed configuration for faster production bootstrap.
fastd/config is the configuration component of the FastD micro-framework — a small, dependency-free container for key/value configuration that can be loaded from PHP array files and injected as a service. It is not a .env/dotenv replacement and does not ship the config() helper (that lives in fastd/framework).
Minimum steps:
composer require fastd/config
use FastD\Config\Config;
$config = new Config();
$config->load(__DIR__ . '/config/app.php'); // file must `return [...]`
$config->get('app.name', 'default');
Where to look first, in order:
src/Config.php and src/ConfigInterface.php — the entire public surface is a handful of methods (load, get, set, has, merge, remove, all). Read this before anything else; it is short enough to read in one sitting.src/Loader/ — the loader contract and the built-in PHP-array loader. This is your extension seam.tests/ — for a package this small, the tests are the actual documentation of merge semantics and dot-notation behavior.ConfigProvider / service-provider class (if present in your version) — how it registers into fastd/container / fastd/di.First real use case: replace a hardcoded array in your bootstrap with config/app.php returning an array, load it once at the entrypoint, and register the instance in the container so controllers and services receive ConfigInterface instead of reaching for globals.
Load order as override mechanism. The cheapest environment strategy with this package is compositional: load config/app.php, then load config/{FASTD_ENV}/*.php on top. Later loads merge over earlier ones, which gives you sane defaults plus per-environment deltas without any templating. Keep the environment name in a single bootstrap variable so the whole thing stays deterministic.
One top-level key per file. Since merges are shallow-ish and dot-get flattens namespaces, name each file's return array after the file (database.php returns ['database' => [...]]). This prevents two files from quietly clobbering each other's keys and makes var_dump($config->all()) readable when debugging.
Resolve secrets at boot, not in files. Don't commit hostnames or credentials into array files, even per-environment ones. In the bootstrap, read getenv()/$_ENV and set() the values after the file loads, or use the package's %placeholder% resolver if your version supports it. Keep the resolution in one function so you can log or assert it in one place.
Wire it as a container service, inject the interface. Register Config (or a read-only wrapper around it) as a shared service, then type-hint ConfigInterface in constructors. This is where the package actually earns its keep: services stop taking five scalar constructor arguments and take one config object, and tests can construct a config with set() only — zero filesystem I/O.
Fail fast on missing critical keys. After all loads complete, add a boot-time guard that checks the handful of keys that must exist (database.host, app.key, etc.) and throws. Configuration typos that produce null at request time are the most expensive class of bug this kind of package enables.
Test fixtures over real config. Point load() at tests/fixtures/config/ in integration tests; use bare set() for unit tests. Never let tests read the project's real config directory — it makes tests order- and environment-dependent.
Skip the caching layer. Array-returning PHP files are already opcache-friendly. Writing a serialized config cache on top adds an invalidation problem for a few milliseconds. Only consider it if you add a non-PHP loader (JSON/YAML/DB).
composer.json, and note that as MIT with ~a dozen files you can vendor it into src/ and own it if the maintainer goes quiet. Budget for that.require on a file without a return yields 1, so you can end up with a scalar silently merged or ignored. Wrap load() in your own helper that asserts is_array() before handing it over.cache.user.1) will be misread by the dot-getter. Avoid dots inside keys, or keep those values in a nested array rather than a flat string key.get() on a missing key is not your safety net. Whether it returns null, false, or throws varies by method and version — always pass the default explicitly, and rely on the boot-time required-key check rather than scattered ??.%...% placeholders often survive into runtime as literal strings. Add a debug assertion that scans all() for leftover % after resolution, at least in non-production.2026-10-27 last-release date is a tag from the FastD monorepo's release train, not a signal of independent maintenance. Judge activity by the commit log on src/Config.php, not by tags.LoaderInterface implementation (JSON/TOML/DB-backed config, or a *.local.php overlay) and a custom resolver for secrets. Both are small, contained additions — this is the one place the package rewards you for reading the interfaces.How can I help you explore Laravel packages today?