Layer 01Production strategy
Outsourced 3D printing throws away your slicer settings. We built a farm workflow that keeps them.
How our UK Bambu farm keeps the orientation, supports, plate layout and profile inside a 3MF instead of discarding it: faithful 3MF mode, a SHA-256 print fingerprint, and a proven-print registry that only trusts a recipe after a QA pass on a real print.

We run a print farm in Huddersfield that peaks at 500+ plates a day across a fleet of Bambu machines, and for the last year we have been building the fulfilment platform in front of it. This is a write-up of the part we think anyone who prints for a living, or designs parts that other people print, might care about: what happens to a slicer project file when you hand it to someone else's farm, and what it took to stop throwing that information away.
The problem: STL-only fulfilment loses the part of the work you already did
The standard outsourced-printing flow accepts an STL, and an STL is a bag of triangles: no orientation you chose, no plate layout, no supports you painted, no per-object settings, no colour assignments, no print profile. Anyone who has spent an evening in Bambu Studio or OrcaSlicer getting a seam off a part's best face knows the mesh is maybe half the work. The other half lives in the project file, and most services discard it at the front door.
They discard it for a defensible reason: trusting a stranger's slicer settings on your machines is risky, and re-slicing everything with a house profile is operationally simple. But for sellers who iterate a design until it prints well and then want a farm to make five hundred of them, "we re-sliced it our way" means the thing that arrives is not the thing they proofed. Orientation changes layer direction, strength and surface finish. Support choices change the scarring. Profile changes move the dimensions of press-fit features. The customer did this engineering already; the fulfilment layer deletes it.
There is a geographic dimension worth stating plainly. Print-farm-as-infrastructure has grown up as a largely US-centric category, which shapes where orders are physically made. For a UK or EU seller, fulfilling from the United States means transatlantic postage on every parcel, plus customs and duty handling each time an order crosses the border. Fulfilling from inside the UK changes those mechanics: shorter domestic and intra-European routes, and no transatlantic customs step on the common case.
3MF fixes the settings problem in principle. A Bambu or Orca 3MF project carries the plates, the transforms, the modifiers, the support enforcers and blockers, the filament assignments and the full print profile. So we made a decision early: faithful 3MF mode is the default. The interesting engineering is in the word "honour", because honouring everything blindly is how you burn a farm's time, and refusing anything you cannot verify is how you end up back at STL-only. The rest of this article is where we drew the lines.
What we preserve from a 3MF, and what we refuse to trust
A quote runs in one of two print modes, recorded explicitly on every quote row: recommended (our profile, our supports, optional infill override) or faithful_3mf (the project sliced as supplied). The modes are not cosmetic. In faithful mode the code path physically cannot send our overrides: the infill override function returns undefined unless the mode is recommended, and the as-supplied supports mode is reserved for faithful quotes. The quote also stores a human-readable assumptions table (material, profile, supports, infill, nozzle) so the seller can see exactly which interpretation they were priced on.
What we refuse to trust is narrower than you might expect, but it is absolute: embedded G-code. Bambu Studio can export a gcode.3mf, a project with the sliced toolpaths baked in as Metadata/plate_*.gcode. We accept the upload, but we never auto-price it and never silently re-slice it. At registration the file is flagged and held for manual review, and the hold is durable by construction: every later quote copies the held review forward instead of enqueuing a fresh slice, and if the held analysis row cannot be found the code fails closed rather than falling through to the re-slice branch. A seller who sliced their own toolpaths did so deliberately; a platform that quietly re-slices with a house profile and quotes on the result has both mispriced the job and discarded the one thing the seller most wanted kept.
Two more boundaries. Multi-plate projects are constrained to one plate per part: a durable plate selection is pinned on the file, and a plate-less quote of a multi-plate project is rejected server-side, not in the UI, so the rule holds for API callers too. And multi-colour projects are detected at registration by parsing the file's colour facts, for reasons covered below.
From upload to priced production specification
The diagram at the top of this article traces the whole route from an upload to a proven print. Here is what each stage actually does.
Every priced quote is backed by a real slice. Each selected file either reuses a recent analysis slice (only when the request is our default profile with no overrides; anything else slices fresh) or goes onto a priority queue for the slicing workers, which run Bambu Studio headless. Guest quotes ride a lower priority than signed-in sellers, so an anonymous upload can never delay a seller's re-quote. Multi-plate files report progress per plate as they slice, and the workspace shows it: a twelve-plate project at fine quality is not a spinner-friendly wait.
The slice comes back as facts, not a price: print seconds, filament grams, support grams, plate count, colour count, slicer version, and, for multi-colour jobs, two numbers that deserve their own paragraph: flush volume in cubic millimetres and tool-change count. On an AMS machine, every filament change purges material into the waste chute and spends real seconds on the swap. Across a plate with hundreds of colour changes, the purge waste can rival the part's own filament and the tool-change time can dominate the print. These are first-class fields on the quote file, and the pricing engine takes them as explicit inputs alongside grams and seconds, with single-colour jobs passing zeroes so their prices are untouched. We are candid about the current state: because the multi-colour maths is newer than the single-colour maths, a job whose detected colour count exceeds one is still routed to a human for pricing. The automated path exists behind a flag and stays off until we trust it, because the failure mode is silent underquoting, and a farm that underquotes purge waste is paying for the privilege of printing.
Aggregation turns facts into a specification. Per-file prices are raw figures; the per-part handling fee and the minimum-unit-price floor apply exactly once at the quote level, so a multi-file part is never double-charged, and the same functions run on the order path so a quote and its order cannot drift. Shipping comes from admin-maintained rate tables keyed on a package format derived from the parts' bounding boxes, not from a live carrier API, after the carrier APIs mis-quoted domestic services once too often. The dispatch estimate folds in material stock on hand and a per-colour restocking buffer. What lands is not a number, it is a production specification: geometry identity, recipe, per-plate slice facts, waste facts, cost breakdown and a dispatch promise, recorded on the quote and minted onto a versioned print option a customer can order against.
Recipe identity: what "we have printed this before" means mechanically
The most useful thing the platform knows is whether an incoming order is a print we have already proven, and "proven" has a precise meaning enforced by a hash.
Every print gets a fingerprint: a SHA-256 over a canonical JSON of three parts. The first is the geometry hash, built from the content hash of each uploaded model file, sorted and combined so the same set of files uploaded in any order hashes identically; a file with no content hash yields no fingerprint at all, and an unhashable print is permanently treated as novel rather than guessed at. The second is the material code. The third is the settings hash, folding exactly the settings that change the toolpath: nozzle size, print mode, quality profile, supports mode and infill density. Missing values normalise to null and keys are sorted before hashing, so the hash is a function of the values, never of key order at the call site.
That "exactly the settings that change the toolpath" is a load-bearing phrase, and we got it wrong once. The classifier that decides whether a settings change needs a fresh slice or just a re-price maintains the same boundary: material, nozzle, quality, print mode, supports, infill and file selection force a slice; colour, quantity, destination, currency and shipping preference only re-price. The fingerprint must fold precisely the first set. An early version folded only nozzle and print mode, so two prints of the same geometry and material that differed only in supports-on versus supports-off, or draft versus fine, hashed identically: a part proven at fine quality with supports would have auto-cleared a later draft, supports-off order nobody had ever validated. The fix was to fold quality, supports mode and infill into the hash, so any toolpath-changing edit yields a new fingerprint that must be proven again.
Two things are deliberately excluded: colour and printer. A part that prints well in black PLA does not become unprintable because the customer chose orange, and it does not become unproven because it lands on a different machine in the same pool. Folding either in would void trust for no engineering reason and send proven work back through the human check. Colour is a per-order attribute by design; changing it never touches the recipe.
The registry side is boring on purpose. When a production job reaches a terminal success (QA passed or complete), its fingerprint is upserted into a proven-prints table: the first proof creates the row and pins which job proved it and when; later proofs only increment a counter and bump the last-proven timestamp. Trust comes from a finished, inspected result, never from the act of slicing or sending a job. The fingerprint column carries a unique index, so two simultaneous QA passes race safely: the loser of the insert re-reads and bumps the winner's row. The gate lookup is one indexed query: does a row exist for this hash.
Automated checks and human judgement
We moved the safety gate rather than removing it. Ordering is open: a settled quote always mints an orderable print option, even one held for manual pricing, in which case the order parks unpaid until the price lands. The real gate is per-order production review, before anything prints. An order is reviewed in pending_review, and approved_for_production is reachable only from that state, with payment status checked at the same transition and a database-level unique constraint ensuring a double-submitted approval cannot create two production jobs.
What the fingerprint registry buys is not less review, it is better-aimed review. An order whose fingerprint is proven skips the human pre-slice check; a novel recipe gets human eyes on the plates before a machine is committed. The reviewer looks at what automation is bad at: does this orientation make sense, will these supports scar a visible face, does this part need a first article before quantity. The automation handles what humans are bad at: remembering precisely, across thousands of parts, which exact geometry-material-recipe combinations have already been through that judgement and come out the other side with a QA pass.
What failed along the way
Headless slicing gives you no pictures. We assumed we would get plate preview images from the slicer, because the GUI shows them and a designer-exported 3MF embeds them as Metadata/plate_*.png, which we extract and store when present in an upload. But a headless Bambu Studio slice does not emit those PNGs into its output, so for STL uploads, which carry no embedded thumbnail at all, there was nothing to show. Previews moved to the client instead: a three.js viewer renders the geometry in the browser and the capture happens there. Wrong layer of the stack, but the only layer that had the pixels.
OpenSCAD substitutes fonts silently. Our text-rendering pipeline (personalised parts: names, labels) runs OpenSCAD in a container, and OpenSCAD's failure mode for a missing font is not an error, it is a quiet substitution to a default. The geometry renders, the job succeeds, and the customer's chosen typeface is simply not the one on the part. The fix is unglamorous: every font the pipeline can be asked for is bundled into the render container as an actual font file; nothing relies on system font resolution. If you run OpenSCAD headless, check this, because nothing in the output will tell you it happened.
Purge waste is a cost centre, not a rounding error. Described above, but it belongs in this list because we initially left flush volume and tool-change count out of pricing entirely, and the first realistic multi-colour test plates made the mistake obvious in filament and hours. They are now first-class quote facts, and their absence on a file with provably multi-colour geometry trips a monitoring alert, because that pricing error otherwise surfaces months later in a margin report.
The slice-relevant boundary is a real design problem. Deciding which settings void print trust looks like a judgement call, and if you make it one, it drifts. Our answer was structural: one classification, defined in one module, used by both the auto-reslice logic and the fingerprint. The incident above is what happens when two parts of the system hold different opinions about that boundary. Now there is one opinion, it is unit-tested, and widening the recipe is a change in one place.
Honest limitations, including the Bambu question
Plenty is still constrained. One production hub. PLA and PETG only. One plate per part. Multi-colour jobs priced by a human. Faithful 3MF mode is subject to production review, so "we honour your settings" means "by default, with a human allowed to disagree before a machine runs". Embedded G-code is accepted but never auto-quoted. Geometry we cannot content-hash never enters the proven registry.
And the fleet question we get asked most: yes, it is an all-Bambu farm, and yes, we have thought about what that dependency means. The machines talk to our farm software over Bambu's local MQTT interface on the LAN; status ingestion into the fulfilment platform goes through one controlled, authenticated endpoint that consumes normalised telemetry events, and the platform never opens printer connections itself, partly because each printer tolerates very few MQTT clients and a second connection drops the first. Slicing uses Bambu Studio, which is open source. The honest risk is firmware: the 2025 authorisation-control changes showed that the boundary of what third-party software may do on the LAN can move. Our mitigations are unexciting and real: we control firmware rollout on our own machines and do not update into restrictions; the printer-facing layer is one seam of the system, with everything above it (quoting, fingerprinting, review, QA) printer-agnostic by construction; and if farm-scale LAN control stopped being viable, the fleet would migrate over hardware refresh cycles to whatever prints as reliably per pound. That would be expensive and slow, and pretending otherwise would be marketing. We chose the machines because they print well and fail rarely at current firmware, and that trade still holds. We keep watching it.