A build step is a bet that the work you are about to do is worth doing once. Rendering a post is cheap. Rendering it forty thousand times because forty thousand people read it is not, and the second number is the one that decides.
So the work moves. It happens once, at build time, and every reader after that gets a file.
What is true at build time is not what is true at deploy time
This is the part that bit us, and it is specific to how the platform orders an install. The build runs before the release is applied. On a brand new project that means the migrations have not run yet, so at the moment the build asks Postgres for posts, there is no posts table.
There are two honest ways out. Deploy twice, and accept that the first deployment is empty. Or make the build responsible for the schema it reads, which is what this blog does: it applies the same two SQL files the release declares as migrations, then queries. Both files are written to be idempotent, so applying them a second time from the release changes nothing.
The result is one command that produces a populated blog on a project that did not exist a minute earlier. The cost is one sentence you have to keep true: the build owns making its data source exist.