Asking for the recommended architecture to pre-provision and preload an image on a backend (Node.js on GCP) and deliver it to an end user as a ready-to-flash file, with zero setup on their side.

We’re designing a one-click onboarding flow for our end users and would like guidance on the right architecture before we
commit to an approach.

What we want the user to experience

  1. The user opens our web app and clicks a single button.
  2. They get back a fully pre-provisioned and preloaded image — already bound to the correct fleet, with the latest release
    baked in.
  3. They flash that image to an SD card and boot. Nothing else. No balenaCLI, no Docker, no Balena account, no first-boot
    configuration screens.

Everything that today is normally done by an operator running balena-cli (provisioning + balena preload) should happen
server-side, on our backend, transparently.

What we’d like the community’s input on

  • Is there an officially supported way to perform balena preload from a backend service? Ideally via the SDK or HTTP API.
    Everything we’ve found so far points to balena-cli / balena-preload, which assume Docker is available on the host and feel
    designed for a developer’s laptop, not for a headless service.
  • What’s the recommended hosting setup on GCP for this kind of worker? Cloud Run / Cloud Functions seem to be out due to the
    Docker-in-Docker requirement and the size of the artifacts. Are people running this on a GCE VM with Docker, on GKE with a
    privileged sidecar, on a Balena-managed builder, or something else entirely?
  • How is concurrency and cost typically handled? Preload is heavy on disk, CPU, and bandwidth — multi-GB images, release
    layers pulled per run. If two users click the button at the same time for the same fleet + commit, we don’t want to pay the
    full cost twice. Is there a recommended pattern for queuing requests and caching preloaded artifacts between them?
  • Is it safe / supported to split the work into a cached expensive step + a cheap per-request step? I.e., cache a
    preloaded-but-unconfigured image per (fleet, commit) in GCS, and only do the per-user configuration injection on the fly
    before serving the download. Or does this break assumptions inside the preload tooling and we should preload + configure
    together every time?
  • What’s the recommended way to deliver the final multi-GB artifact to the user? Streaming the file directly out of the
    preload worker into the HTTP response, or pushing it to GCS and handing the user a signed URL? Any guidance on resumable
    downloads so a flaky connection doesn’t force the user to start over?

Environment

  • Backend: Node.js + TypeScript, planning to use balena-sdk.
  • Hosting: GCP.

Any reference architectures, sample setups, or “don’t do that, do this instead” advice would be hugely appreciated before we
lock in a design.

Unfortunately this is not possible to day, the current preloading mechanism requires a process to be able to mount the OS image data partition as a volume to a docker engine to then do a pull of the images from our registry. So to do this as an service, you would need a server capable of running a docker-in-docker setup and then re-implement the set GitHub - balena-io-modules/balena-preload: Script for preloading containers onto balena device images · GitHub does to expand the partiion and get the images on to the /data . The easiest option would probably be to create a web service that wraps the balena-cli in an HTTP interface. This is something we do have planned in our future roadmap, but it won’t happen in the next year. Further in the future, it may also be possible to use tools like skopeo to make this much easier, but that will require balenaOS migrating to the containerD imagestore or podman, both of which are non-trivial and will take time.