Two Packages, One 2 GB Server: Requirements.txt as Product Discipline
The first batch I ever ran twice returned 39 rejected CSVs in under a minute. Not because my art was bad. Because I had fat-fingered a header and then re-run the upload script, and every channel treated the second pass as a fresh submission. One mistake, a whole evening gone. That day I learned that the most expensive things in a product pipeline are not render times. They are the small, dumb, repeatable errors that a script should have made impossible.
This post is about that lesson, and about something that surprised me while cleaning up the kit built from that mess: the strongest proof of discipline in a pipeline is often a tiny requirements.txt.
The requirements file is a promise to yourself
The pipeline starter kit has four scripts. make_metadata.py builds upload CSVs. upload_tracker.py is the double-post ledger. md2pdf.py turns Markdown into a PDF. pack_product.py zips files and renders a cover at 1280x720 plus a thumbnail at 600x600.
Two of those need third-party packages: Pillow for covers, reportlab for PDFs. The other two need nothing at all, just the standard library.
So the install is two lines in requirements.txt. Not fourteen. Not a framework, not an SDK, not a cloud client. When your dependency list is that short, every package you add has to justify itself against the 2 GB machine it has to run on. That is not minimalism for its own sake. It is a budget, and the same instinct that says "no" to a new package is the instinct that says "no" to running your batch twice.
The rules a 2 GB box will teach you
This entire pipeline ran on 1 vCPU, 2 GB RAM, no GPU, and it packaged 39 products totaling 856 MB of output. That is not a flex. It is a constraint that forced the code into better habits:
- One process at a time. Never fan out image jobs in parallel on a single core.
- Free memory between items with
gc.collect()after each asset. - Measure peak RSS, not average, using
resource.getrusage(RUSAGE_SELF).ru_maxrss. - Process one file per subprocess for heavy render steps, so memory goes back to the OS.
- Render at the resolution you need. A 60 dpi preview will tell you what a 300 dpi render at the wrong size will not.
Every one of those habits is also a reliability habit. A pipeline that never runs out of memory is a pipeline that finishes the batch, and a pipeline that finishes the batch once is a pipeline you do not re-run by accident.
The platform rules that eat whole evenings
The four scripts exist because of four specific failure points, and each one has a hard rule attached.
Metadata. Adobe wants a 5-column CSV. Vecteezy wants 4 columns. Dreamstime wants 15. Get the header wrong and the upload is rejected instantly. make_metadata.py writes the header the channel demands and nothing else.
Double posting. The fastest way to get an account flagged is submitting the same batch twice. upload_tracker.py is a ledger. pending items.txt shows what you have not posted. done "asset-001.jpg" marks it. A re-run physically cannot double-post because the script checks the ledger first.
Docs into products. You already have the content. md2pdf.py content.md product.pdf "My Product Title" makes it look like a product in one command.
Packaging. A zip with a real cover sells. A bare file does not. pack_product.py my-product "My Product" "A short subtitle" 9 writes the zip, the cover, and the thumbnail into a _system folder, or wherever --dir or PACK_ROOT points.
Note how small each rule is. None of them needs a service. None needs a database. They are all just scripts that refuse to guess.
The folder layout is part of the requirements
A catalogue becomes a junk drawer within a week unless you fix the structure first. The kit assumes one shape:
project/
assets/ raw output, one file per asset
output/ ready-to-submit files plus metadata.csv
packs/ finished zips and covers
research/ your notes and sources
scripts/ these tools
The one rule I will defend hardest is keeping research/. Those scrape logs and notes are raw material for the next product. Deleting them to "clean up" is a mistake this project made once and is not repeating.
What is actually inside the kit
Four standalone Python scripts. No framework. No cloud account. Python 3.9+.
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
If you only use the metadata and tracker scripts, you can skip the install entirely. They need nothing but Python.
Opt into real labels with --titles titles.json when you have them. Without it, the filename is title-cased and used as the title, which is fine for a first pass and wrong for a submission.
The honest part
These scripts came out of a parent project with roughly 19,000 lines of pipeline code and more than 300 pages of research behind the rules they enforce. I cut it down because the rules did not need 19,000 lines. They needed four scripts, a short requirements file, and the discipline to not add to either.
Building digital products? Free guides & kits for digital product sellers.
Top comments (0)