DEV Community

Cover image for Two Packages, One 2 GB Server: Requirements.txt as Product Discipline

Two Packages, One 2 GB Server: Requirements.txt as Product Discipline

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Get pipeline starter kit


Building digital products? Free guides & kits for digital product sellers.

Top comments (0)