Build1 distinct publisher3 min readPublished
A census puts a number on a fork nobody in these projects argued about, and the schemas that declare no relationships still work fine, because Eloquent holds what the database was never told.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
The keyless password reset table survives because nothing in the running application ever asks for a primary key. The scaffold declares email and token NOT NULL, created_at nullable, and one non-unique KEY on email [6]. The lookup path the app uses is indexed, so no query gets slower and no test goes red. What the DDL as printed also permits is two rows for the same address, because a non-unique index with no PRIMARY is no uniqueness at all [7]. Twill is the evidence that this was inherited rather than chosen: it renamed its copy to twill_password_resets in its own migration and left the keys alone [8]. The rename touched the table name only; the primary key and index stayed exactly as the scaffold had set them.
Foreign keys turn out to be just as sparse as the missing primary keys. Snipe-IT is a mature asset manager with 58 tables held together by exactly one foreign key [10]. Cachet sits in the middle with 32 tables and three keys, about one per eleven tables [13][4], and its schema is full of columns that name their target with _id, in the right type, next to the table they point at [13]. The ->foreign() call is the only interface between an Eloquent relationship and a database constraint, and where no migration outside vendor/ makes that call, the models are the only place the relationship exists [11]. Alberto Arena attributes part of the split to portability: several of these projects ship migrations meant to run on MySQL, PostgreSQL and SQLite alike, and he names the foreign key as the main casualty of that choice [12].
For the roughly-half figure to transfer to your codebase, the incentive has to transfer with it. Every application in the census is a codebase you can clone and read [1], so each one installs onto a database somebody else administers, which makes multi-engine migrations a product requirement rather than a preference [12]. If your Laravel app runs on one engine you own, that constraint never applied to you, and you can still end up with the schema it produces, because the framework and the ecosystem around it chose first [2]. The relationships in the schema-free half are real; they live where an ER diagram cannot see them [14].
Two coverage lines are worth copying down alongside the numbers. Relationship counts cover all fifteen applications, less Statamic, which the census holds out of that ranking for a reason handled in its own section, leaving a ranking fourteen wide [3][9][5]. The structural checks cover twelve databases and 482 tables, of which seven are real applications and five are bare Laravel baselines kept as a control [4], so eight of the fifteen never ran the tooling that found the keyless tables [2]. Six is a floor. At 811 tables across fifteen applications the corpus averages about 54 tables each [1], which is a workable definition of past the tutorial stage [2].
The generic form of this is that whichever generator wrote your first ten migrations still owns them until somebody reopens the file, and that is the mechanism the census documents rather than any failure of care in the four projects still carrying the old shape [2].
Ranked by verification strength, evidence, and original report placement.
The piece is described not as a review of the fifteen projects but as a census of what a Laravel schema looks like once an application has shipped and grown past the tutorial stage; the author says these projects share conventions they never discussed because the framework or the ecosystem around it chose first, and that the keyless-table finding says something about how Laravel scaffolding propagates rather than about carelessness in the four projects that still carry it.
The relationship counts cover all fifteen applications.
The structural checks are slower and some applications could not run the tooling at the time, so they cover twelve databases and 482 tables, of which seven are real applications and five are bare Laravel baselines kept as a control.
Several of the projects ship migrations designed to run on more than one database engine, MySQL, PostgreSQL and SQLite alike; the author says that choice has a direct, visible cost in the schema and that the foreign key is the main casualty.
Cachet has 32 tables and 3 foreign keys between them, with a schema full of columns clearly meant to reference another table, using _id naming, the right type, and sitting right next to the table they point at.
The census covers fifteen real Laravel applications, each a publicly readable codebase, totalling 811 tables, read against one pinned MySQL 8.0 database using migrations only and no seed data, with every application installed from a clean clone and migrated before a single table was read.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 28, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
Once the question needs a cube, you own the parser1 distinct publisher
build
EF Core's defaults pass code review, then meet the second replica1 distinct publisher
build
The ICO fines what you cannot prove: Article 32 makes encryption and erasure an engineering liability1 distinct publisher
build
Object or file storage: the wrong pick stays quiet until inode exhaustion1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Method spelled out, headline table withheld
The procedure is more explicit than most reporting of this kind: one pinned MySQL 8.0, clean clones, migrations only, no seed data, five bare Laravel installs kept as a control, and the two reads held apart so no figure borrows credibility from the other set. The quoted DDL and the ->foreign() grep result are the sort of detail a reader can verify against public code. What is not on the page is the ranked relationship table itself — only Snipe-IT, October CMS and Cachet appear as numbers — and the tooling behind the structural checks is named nowhere, even though which applications could run it decides who is in the 482-table set.
Counted off software people already run
Nothing here is a proposal or a preview — every figure comes from schemas that exist in shipped, self-hostable products: an asset manager, a CMS, a status page, an accounting tool. The keyless scaffold is not a hypothetical either; it is still in four of them, years after Laravel replaced it, and Twill carried it through a rename of its own. What keeps this short of a full picture is that the measurement is a snapshot of open-source codebases only: private applications, which the write-up itself notes face no multi-engine portability constraint, are entirely outside the count.
Disciplined prose, unshown arithmetic
The restraint is real and deliberate: the bottom of the foreign-key list is explicitly not a quality ranking, portability is offered as the reason Cachet declares three constraints for thirty-two tables, and the keyless tables are attributed to a generator rather than to four teams' inattention. The overreach is narrower and sits in the superlatives — 'the strongest finding', 'split evenly', 'nobody had put a number on this before' — each of which leans on a table the reader never sees and on a threshold for 'almost no lines' that is never defined. Believe the specimens; hold the headline fraction loosely.
No product in the frame, one unnamed tool
Follow the money and it runs out quickly: no vendor, no sponsor, no service that happens to solve the problem being described, and the real issues found during the read were routed privately to the owning projects instead of being spent as material. The single unresolved thread is the tooling that produced the structural checks — invoked only to explain which applications fell out of the 482-table set, never named or attributed — and an unnamed ruleset is the one place a commercial interest could sit unremarked. dev.to is also a self-publishing venue, so the usual reputational upside of a big-sounding number applies.
One voice, but a checkable one
Confidence rests on reproducibility rather than corroboration. Fifteen public codebases and a pinned engine mean anyone with an afternoon can confirm or break these counts, and the specimen-level claims — Snipe-IT's single foreign key, October CMS's zero, the six identical keyless tables — are the kind that fail loudly if wrong. Against that: nobody has done it, the ranked table is missing, and the Statamic explanation breaks off mid-sentence, so the least-verifiable part of the story is exactly the part the headline uses.