streams/core
The core of Streams, a modular Laravel framework for building data-driven applications and CMS-style platforms. Define database-driven streams, fields, and addons, then manage everything through a powerful control panel. Extensible, developer-friendly, and built for rapid development.
streams/core is not a package you sprinkle into an existing Laravel app — it is the engine layer of an application platform. It gives you streams (tables), fields (column behavior), assignments (which fields belong to which stream), a repository + criteria query layer, and an addon registry. It does not give you a control panel or admin UI; that lives in the sibling packages. Plan for core-only to mean "I get config-driven models and a query abstraction, and I build my own screens."
Minimal setup:
composer require streams/core and confirm the resolved sibling packages (streams/*) agree on your Laravel/PHP constraint. This is the single most likely place to get stuck — read composer why-not output before writing any code.streams:install / compile step). You now have the metadata tables that describe your streams.streams/ directory tree (a namespace/slug layout with a stream config file), not authored by hand in database/migrations.Where to look first, in order:
config/streams.php — field type registry, cache settings, routing/entry model overrides. This file answers most "why is it doing that?" questions.Criteria base class and the Repository class — this is the cleanest part of the package and the part you will actually use daily.First use case worth building: a single stream with two field types (e.g. title string, price integer), one repository query with a custom criterion, and one create/update path. Keep it in a greenfield module or a scratch app. Do not retrofit an existing table into a stream for your first attempt — you will spend the day reverse-engineering migrations instead of learning the paradigm.
Definition-first workflow. The loop you will repeat is: edit the stream definition file → add/adjust fields → run the engine's migration/compile command → use the repository. Schema is derived from configuration, so the config file is the source of truth and the DB is a build artifact. Get comfortable treating generated tables as disposable in development.
Repository + criteria as your seam. The repository/criteria pattern is the package's genuinely good idea and also your only real exit route. Wrap it:
interface PostRepository {
public function published(int $limit): iterable;
public function create(array $attributes): object;
}
Implement it with Streams repositories and criteria internally; callers depend on your interface. If the package is later abandoned, you rewrite one class instead of grep-and-replace across the app.
Criteria for anything reused. Inline where() chains on the repository work, but the moment a condition appears twice, promote it to a Criteria subclass. Criteria are composable, testable in isolation, and roughly the equivalent of a query scope — they are the closest thing to a Laravel idiom the package offers, so lean on them heavily.
Field types for domain primitives. Anything with custom formatting, casting, or validation (money, address, slug, geo) should be a field type rather than ad-hoc accessors on entries. Then the behavior travels with the definition and shows up correctly for anyone reading the stream config. Register custom types explicitly and namespace them — the registry is flat and collisions across packages are real.
Keep streams on one side of the wall. Do not let stream definitions become the schema of record for core business entities. Use Streams for configurable/low-risk domains (catalogs, content types, internal tooling data), and leave your main models on conventional Eloquent with authored migrations. The engine overrides entry models and query behavior globally; the more surface you hand it, the more non-stream code it can surprise.
Seeding and fixtures. Seeding through entries is slower than raw inserts and is affected by field-type casting. For large fixture sets, seed the underlying table directly once the schema is stable, and reserve repository writes for testing the write path itself.
Cache the metadata. Stream and assignment resolution walks config on the hot path. Enable the package's metadata cache in non-local environments, and make "recompile after changing a stream" an explicit step in your deploy script and your local dev loop.
NOASSERTION. Before you write feature code, confirm the actual license from composer.json / the repo and get sign-off. This is a hard gate, not a checklist item — it has killed adoptions of this package before.composer why-not laravel/framework and a smoke test before every framework bump.$casts and relationship methods. Don't reach for ->save(), $model->relation, or mass-assignment guards out of habit — read the entry API first.tinker in, dump the compiled stream config, dump the assignment list, then dump the generated SQL from the repository. That sequence separates "definition wrong," "cache stale," and "query wrong" in three steps instead of an hour.How can I help you explore Laravel packages today?