Build Cargo
KINDAback to the verdict
A site builder whose hard problems are a content model that survives a redesign, images that do not cost a visitor their data allowance, and a publish that is atomic and reversible rather than a file by file sync over a live site.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the editor and the build.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree
Why Derivative generation at several widths is the difference between a fast site and a slow one, and doing it by hand does not happen.
Get it Any maintained library that resizes and re-encodes, installed as a dependency.
Verify
It produces a resized file at three widths from one original - accountfree to a few pounds a month
Why Atomic publishing needs a host where you can upload a release and then switch, rather than one that only offers a file by file sync.
Get it Any static hosting or object storage you already have, plus its published limits page.
Verify
You can upload a directory and serve it, and you have read the limits page - have readyaround ten pounds a year
Why Domain and certificate handling is the part that breaks on a Friday, and testing it against a real name is the only test that counts.
Get it Any registrar, with access to the DNS records.
Verify
A record you add resolves within an hour - decidefree
Why Web embedding is a separate permission from desktop use, and the build refuses to run without the note.
Get it For each font, record the licence and one sentence on whether web embedding is permitted.
Verify
Every font file in the project has a note beside it and the build passes
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- sites(id, name, base_url, primary_domain, created_at) - pages(id, site_id, slug, title, description, status, ordinal, updated_at) · slug is unique per site and changing it records a redirect - sections(id, page_id, ordinal, kind, content_json, layout_json) · typed sections with layout options, never absolute pixel positions - assets(id, site_id, original_path, sha256, width, height, bytes, alt_text) · alt text lives with the asset, not with one use of it - derivatives(asset_id, width, format, path, bytes) · generated at publish, safe to delete, regenerated on the next build - releases(id, site_id, built_at, output_dir, file_count, bytes_total, published_at, rolled_back_at) - redirects(site_id, from_path, to_path, created_at) · because a renamed page that returns nothing is how a site loses its links
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_PATH | required | ./data/site.db | Pages, sections and assets. A working copy of the JSON export. |
CONTENT_EXPORT_DIR | required | ./content | JSON written on every save. This is the copy that outlives the editor. |
ASSETS_DIR | required | ./assets/originals | Untouched originals. Never included in a release. |
BUILD_DIR | required | ./releases | One directory per release, kept for rollback. |
IMAGE_WIDTHS | required | 400,800,1200,2000 | Derivative widths emitted into srcset. |
MAX_FILE_BYTES | required | 1500000 | The build fails if any released file exceeds this. |
RELEASES_KEEP | required | 5 | Previous releases retained. This is what rollback uses. |
DEPLOY_TOKENsecret | optional | sk-...redacted | Only if your host needs one to upload. Unset means you publish by hand. |
The build, in order
A content model, not a canvas
Pages are typed sections, so a redesign changes the renderer and not the content.
Five kinds that fit is better than one kind that holds anything.
Files
src/schema/sections.tsOptions survive a redesign; coordinates are the redesign.
Files
src/render/section.tsxSo the content is readable without the editor from day one.
Files
src/content-export.ts
done when · tick each as it passeswatch out- A freeform canvas that stores each element at an absolute pixel position looks like the product people want and produces a site that is unreadable on a phone, impossible to restyle, and stuck with whichever font metrics the editor had that day. Store typed sections with layout options and let the renderer decide where things go.
Images that do not cost a visitor their data allowance
Every image ships at a sensible size with dimensions declared.
Not at request time, because there is no server to request from.
Files
src/build/images.tsThe cheapest fix for a page that jumps while it loads.
Files
src/render/image.tsxA warning nobody reads is how a site ends up with none of it.
Files
src/build/checks.tstests/alt-text.test.ts
done when · tick each as it passeswatch out- Shipping the original from a camera and constraining it with a hundred percent width rule sends a twelve megabyte file to a phone to be displayed at four hundred pixels, and without declared dimensions the page jumps as each one lands. Generate derivatives at publish, emit srcset, and always write width and height.
A build that is just a folder
The same content builds to the same bytes and needs nothing running.
Sort everything, and keep timestamps out of the output.
Files
src/build/index.tstests/deterministic-build.test.tsSo caching is aggressive and still correct.
Files
src/build/assets.tsIt is what publishing, rollback and the size check all read.
Files
src/build/manifest.ts
done when · tick each as it passeswatch out- Rendering pages from the database on request means the site is only alive while your builder is, so the moment the process dies or the disk fills the whole site is gone rather than merely un-editable. Build to files, and treat the database as a working copy of something that already exists on disk.
Publishing that is all or nothing
Visitors see the old site or the new one, never a mixture, and you can go back.
The switch is the only moment anything changes for a visitor.
Files
src/publish/upload.tsCount and hashes, because a truncated upload looks like a successful one.
Files
src/publish/verify.tsThe night you need it is not the night to find out it was never written.
Files
src/publish/rollback.tstests/rollback.test.ts
done when · tick each as it passeswatch out- Syncing the build over the live site file by file leaves visitors during the upload with new HTML asking for stylesheets that are not there yet, and a failure halfway leaves the site permanently in that state with no way back. Upload a whole release, verify it, switch, and keep the previous one so rollback is one command.
Fonts, domains and the ability to walk awayproduct builder
The site keeps working without the builder, and every asset in it is one you may use.
One sentence per font, checked by the build, saves a legal conversation.
Files
src/build/fonts.tsContent, originals and the release, in one archive.
Files
src/export.tstests/rebuild-from-export.test.tsA renamed page that returns nothing is how a site loses its inbound links.
Files
src/redirects.ts
done when · tick each as it passeswatch out- Converting a font bought for desktop use into a web format and serving it is a licensing decision most people make by accident, and it is the kind of mistake that arrives as a letter rather than a bug report. Record a licence note per font, check that web embedding is permitted before you ship it, and let the build fail when the note is missing.
That is the whole plan for Cargo. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Forms and comments.
- A template marketplace.
- Multi user editing and client handoff.
- Commerce.
- general-purpose visual editing
- large template and component libraries
- CMS collaboration and client handoff
- managed hosting, forms, and analytics
- A second theme sharing the same content, which is the test of whether the model really is separate from the layout
- Scheduled publishing, which is the existing publish behind a timer and nothing more
- A link checker in the build, so a broken internal link fails before visitors find it
Need the files? The project pack on the verdict page hands your agent the whole brief · more website builders.