What Via Learns from Heroku

This follows Introducing Via, which lays out the platform before comparing it with older deployment systems.

Heroku made deployment feel small.

Before that, shipping a web app often meant learning a server, installing packages, configuring a process supervisor, wiring logs, and hoping production still looked enough like the developer's laptop. Heroku changed the shape of the job: give the platform source, let it build the app, attach config, start processes, and show what happened.

That is the part Via should steal.

The Heroku move

Heroku was founded in 2007 by James Lindenbaum, Adam Wiggins, and Orion Henry. It started with Ruby app hosting, launched commercially in 2009, added a marketplace for add-ons in 2010, and joined Salesforce after the December 2010 acquisition.

The famous command was simple:

git push heroku main

The command was not the whole story. The useful part was the lifecycle behind it. Heroku received source, detected the app, built a slug, attached config, ran dynos, streamed logs, and made the app operable.

The Twelve-Factor App gave names to much of that model: strict dependencies, config outside code, backing services as attached resources, build/release/run as separate stages, disposable processes, and logs as event streams. Those ideas outlived Heroku's original Ruby focus. They show up in hosted platforms, internal developer platforms, and app runners that do not look much like Heroku.

The lifecycle

Source selected by developer Platform receives source Build and test Create release with config Start runtime Status, logs, audit
Source selected by developer Platform receives source Build and test Create release with config Start runtime Status, logs, audit

That split is worth keeping. Source is not the production artifact. A build is not yet a release. A release is artifact plus config. A runtime instance is replaceable. Logs and status belong to the platform.

Via's version

Via takes the Heroku model, but not the exact interface.

The main workflow is:

vary app deploy my-app --target prod

The command sends source to Via and follows the operation. Under the hood, Via may use Git, deploy tokens, pre-receive validation, and server-side repository storage. Users should not have to add a Via Git remote, manage credentials, or remember refspecs. The command is the interface.

That fits Via Server: app owners submit source, and the platform owns the controlled path to a running service. It also matches Golden Path: Install Via and the Echo Server, where deploy, config, routes, and runtime status are one workflow instead of four unrelated chores.

Heroku lessonVia choice
Source is the deploy inputvary app deploy sends source to Via.
Build happens on the platformVia checks out, typechecks, tests, packages, and signs.
Release includes configVia combines artifact, config profile, secrets policy, add-ons, and route state.
Services are attachedManaged SQLite and future add-ons are named bindings.
Logs belong to the platformVia records operations, deploy states, runtime logs, and audit events.

The same pattern shows up in managed SQLite: the app asks for a named binding, and Via owns the operational resource.

Branches and tags

Via should keep the familiar Heroku branch idea without making Git the user interface.

An app can have a configured deploy ref, defaulting to main. A normal deploy uses the current source and sends it to that deploy ref:

vary app deploy my-app --target prod

A developer can deploy another branch to the app's deploy ref through the Vary command:

vary app deploy my-app --target prod --ref feature-x --deploy-ref main

That means what people expect from Heroku-style branch mapping: take this branch and deploy it as the app's main release line. The internal transport can use Git mechanics. The user does not need to see them.

Tags should be explicit:

vary app deploy my-app --target prod --tag v1.2.3

Via should record the tag and the resolved commit. If the tag moves later, that is a new event, not a rewrite of an old deploy.

Where Via should be picky

Via should hide Git mechanics from users, but it still has to be strict inside the receive path.

RuleReason
The Vary command owns deploy credentials.Deploy tokens stay short-lived, scoped, and outside normal Git credential storage.
Accepted source must be buildable.If the builder cannot check out or archive it, the platform should reject it before creating a deploy.
Ref names normalize everywhere.main, heads/main, and refs/heads/main should mean the same deploy ref.
Git failures become Via errors.Non-fast-forward, stale hook, expired token, and wrong-ref failures need stable Via codes and next commands.

This is where Heroku is an influence, not a template. The simple experience is worth preserving. The raw Git edge cases are not.

The lesson

Vary tries to make application contracts explicit: HTTP contracts, typed handlers, generated clients, managed persistence, config, secrets, and tests. Deployment should live at the same level.

The useful lesson from Heroku is plain:

source in
platform-owned build
platform-owned release
platform-owned runtime
clear status out

For Via, the command is vary app deploy. The platform receives source, builds from a clean checkout, signs the artifact, attaches declared resources, starts a verified runtime, and records the path.

That is the Heroku idea worth keeping.

References

SourceWhy it matters
Heroku company historyTimeline for Heroku's founding, launch, add-ons, Postgres, and Salesforce acquisition.
Heroku Dev Center: How Heroku worksHeroku's own description of app lifecycle, builds, releases, dynos, config vars, and add-ons.
Heroku Dev Center: Deploying with GitThe branch deployment model that informs Via's branch semantics.
The Twelve-Factor AppThe app design model behind source, build, release, run, config, and logs as platform concerns.