Release Management

Release management is how you move the SaaS package you built (its screens, entities, workflows, pricing, roles, and AI skills) from your sandbox to your customers without breaking anything live. Every release is a complete, hash-verified snapshot of the package. You promote it through environments in a fixed order, gate the higher environments behind approvals, roll out gradually, and roll back to a known-good state in one action. Every step leaves an immutable, tamper-evident record you can hand to an auditor.

Pro Release management is part of the Backbuild Pro build-and-ship platform, alongside multiple environments and the SaaS marketplace. See pricing.

A left to right pipeline. One frozen, hash-verified snapshot flows from Draft into Development, then Staging, then Pre-production, then Production. The arrow into Development is marked fast iteration, no quorum. The arrows into Staging, Pre-production, and Production each carry an approval gate that requires four-eyes sign-off. Every arrow moves the same hash-verified snapshot, because nothing is rebuilt between stages. A curved return arrow from Production loops back to a prior stage, labelled rollback: one action, back to a known-good snapshot.
One snapshot is promoted through Development, Staging, Pre-production, and Production. Development takes it without a quorum; every later stage is gated by a four-eyes approval, and the identical hash-verified snapshot moves through unchanged. Rollback returns any environment to a known-good snapshot in one action.

What a Release Is, and What It Captures

After this section you will know exactly what gets frozen into a release, and what does not, so what you test is what ships. A release is a versioned snapshot that captures the full state of a SaaS package at a single moment. When you create one, the system freezes the current configuration into an immutable record, computes a SHA-256 hash over its contents, and assigns it a version number automatically. From then on that snapshot never changes: it is the unit you promote, approve, and roll back to.

The number-one worry builders bring to promotion is that the snapshot quietly leaves something out, so production ends up different from what they tested. It does not. A snapshot captures every configurable part of the package:

Component What is captured
Package metadataName, description, version, owner.
Pricing plansAll pricing tiers, billing intervals, and amounts.
Screen definitionsUI screen layouts and component configurations.
Seed dataDefault data loaded for new tenants.
Entity typesCustom entity type schemas and field definitions.
WorkflowsWorkflow definitions, triggers, and automation rules.
AI skillsCustom AI skill configurations and prompts.
ViewsSaved filter and sort configurations.
Roles & permissionsCustom roles and permission mappings.
Connector configsThird-party integration configurations.
App configsApplication-level settings and feature toggles.
Data bundlesStatic data packages and asset references.

What a release does not contain: your customers' live tenant data. A release is the configuration of the product, not the records your tenants create inside it. Promoting or rolling back a release changes the packaged configuration; it never touches, moves, or reverts live customer data. Keep that boundary in mind: rollback restores the app you shipped, not the data your users entered after it shipped.

Cut Your First Release

After this section you will be able to turn your current working package into a versioned release. Creating a release takes two pieces of information: a name and, optionally, notes. Everything else, the snapshot contents, the hash, and the version number, is captured for you.

FieldRequiredMeaning
release_nameYesA human label for this release, 1 to 200 characters.
release_notesNoFree-form notes, up to 10,000 characters, describing what changed.

You do not supply a version number. The system assigns the next integer version automatically (one higher than the previous release of this package), so versions are always sequential and never collide. The new release starts in draft status.

POST /v1/saas-packages/019d.../releases
Authorization: Bearer $TOKEN
Content-Type: application/json

{
  "release_name": "Q3 pricing and workflow update",
  "release_notes": "Adds workflow automation and two new pricing tiers."
}

# Response
{
  "id": "019e...",
  "version": 7,
  "release_name": "Q3 pricing and workflow update",
  "release_notes": "Adds workflow automation and two new pricing tiers.",
  "snapshot_hash": "sha256:a1b2c3...",
  "status": "draft",
  "created_by": "019d...",
  "created_at": "2026-07-16T10:00:00Z"
}

The response returns the release metadata, not the full snapshot. The version is an integer, and the snapshot_hash is the fingerprint that lets anyone confirm later that the snapshot has not changed.

The Create Release page for a SaaS package. Callout 1 marks the Release Name field, filled in with Q3 pricing and workflow update. Callout 2 marks the Release Notes field describing what changed. Callout 3 marks the live character count next to the notes. The package's draft state is shown as a draft chip in the top right.
Creating a release takes only a name and, optionally, notes. Everything else, the snapshot contents, the hash, and the integer version, is captured for you, and the new release starts in draft.

Compare Versions and Pin Every Resource

After this section you will be able to see exactly what changed between two releases, and trust that nothing drifts as it moves to production. Before you promote, you want a readable answer to “what actually changed since last time?” The diff view compares two release snapshots and reports what was added, changed, and removed across the package.

GET /v1/saas-packages/019d.../releases/diff?from=019e...&to=019f...
Authorization: Bearer $TOKEN

Every release also records a version-pinned manifest: each captured resource (each screen, entity type, workflow, pricing plan, and so on) is stored with the exact version it had at snapshot time. You can list those pinned items to see, resource by resource, precisely what this release contains.

GET /v1/saas-packages/019d.../releases/019e.../items
Authorization: Bearer $TOKEN

Because promotion carries the same immutable, hash-verified snapshot forward, there is no environment drift. What you approved in staging is byte-for-byte what deploys to production. The pinned manifest and the snapshot hash together guarantee it.

The Release Lifecycle

After this section you will understand the status a release moves through, and why a release must be approved before it can deploy anywhere. A release has a status that gates what you can do with it. You advance the status as the release is validated.

StatusMeaning
draftJust created. The snapshot is frozen, but the release is not yet cleared for deployment.
testingUnder validation. Reviewers are exercising it and recording findings.
approvedCleared for deployment. A release must reach this status before it can be deployed to any environment.
rejectedTurned down. It will not deploy until it is re-worked and re-approved.
archivedRetired from active use, retained for the record.

The important rule: a release must be in approved status before it can be deployed to any environment, including development. This keeps a half-finished snapshot from being pushed anywhere by accident.

PATCH /v1/saas-packages/019d.../releases/019e.../status
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "status": "approved" }

Promote Through Environments

After this section you will be able to move a release from development to production in the correct order, and you will understand why the system refuses to let you skip a stage. Releases are promoted through four environments, each with a clear purpose.

StageEnvironmentPurpose
1DevelopmentFast iteration. You deploy here to try the release out and move quickly.
2StagingIntegration validation of the full configuration under production-like conditions.
3Pre-productionFinal validation in a production-like environment before going live.
4ProductionLive deployment serving your real users.

You deploy a release with the environment field. A deploy supersedes whatever release was previously active in that environment and records the change in the deployment history.

POST /v1/saas-packages/019d.../releases/019e.../deploy
Authorization: Bearer $TOKEN
Content-Type: application/json

{
  "environment": "staging",
  "notes": "All dev checks passing, ready for staging validation."
}

Sequential promotion is enforced, not suggested

Skipping a stage is refused, not merely discouraged. The order is enforced at the moment you deploy:

  • Deploying to staging has no prerequisite.
  • Deploying to pre-production requires an active staging deployment of that release.
  • Deploying to production requires an active pre-production deployment of that release.

Attempting to jump ahead returns a precondition failure. This is what makes “we validated it at every level before it went live” a fact you can prove rather than a process you have to police by hand. A classic audit finding, a deployment that predates its own approval, cannot happen when the order and the approvals are enforced together.

Development stays fast

Development is for rapid iteration, so a deploy to development skips the approval quorum and the separation-of-duties check. It still requires the release to be in approved status, but it does not wait on a review panel. The gating you configure applies to staging, pre-production, and production. That is the balance most teams want: fast in dev, gated where it counts. When you need an urgent fix in the higher environments, the change still moves through the same gates; you satisfy them quickly by having the required approvers act, rather than by turning the control off.

See What Is Live: Status Board and History

After this section you will be able to see, at a glance, which release is live in each environment, and the full history of every promotion. The environment status view shows the current deployment per environment, so you always know what is running where.

# Current deployment in each environment
GET /v1/saas-packages/019d.../environments
Authorization: Bearer $TOKEN

# Full promotion history (paginated, filterable by environment)
GET /v1/saas-packages/019d.../environments/history
Authorization: Bearer $TOKEN

The history is an auditable trail of every promotion: which release, to which environment, by whom, and when. It is the record a release coordinator uses to answer “who deployed what, and when?” without reconstructing it from chat.

The Release Management screen for a package before its first release. The release pipeline runs left to right: Draft, a Dev Gate marked No Policy, Development showing Live Data, a Staging Gate marked Pending, Staging Not deployed, a PreProd Gate Pending, Pre-Prod Not deployed, a Prod Gate Pending, and Production Not deployed. Callout 1 marks the New Release button, callout 2 marks Development running on live data with no quorum, callout 3 marks a pending approval gate that guards staging, pre-production, and production, and callout 4 marks the Production environment status.
The environment pipeline shows at a glance what is live in each environment and which gate guards each promotion. Development takes releases without a quorum; every later stage sits behind an approval gate. This package has no releases yet, so every environment reads Not deployed.

Approvals and Separation of Duties

After this section you will be able to require the right people to sign off before a release reaches a gated environment, and you will understand why an approval cannot be reused or self-granted. An approval policy defines who must approve a promotion into a given category of environment. Policies are optional per category; where one is active, its full rule tree must be satisfied before the deploy is allowed.

Approval policy categories

CategoryApplies to
staging_promotionPromoting into staging.
preprod_promotionPromoting into pre-production.
production_deploymentDeploying to production.
security_reviewA security sign-off requirement.
compliance_reviewA compliance sign-off requirement.
rollback_authorizationAuthorizing a rollback.

Rules: N-of-M, roles, groups, and AND/OR

A policy’s rules field is a tree of conditions combined with AND and OR, so you can express anything from “any one VP” to “two of five senior engineers, and one security reviewer.” The leaf conditions are:

ConditionSatisfied when
specific_usersThe named users have approved.
roleA required number of holders of a role have approved (N-of-M).
groupApprovals come from a group, optionally requiring a number from each named group (from_each).
cross_roleApprovals span more than one distinct role, so no single team can clear a change alone.

Combine leaves with AND (all must hold) and OR (any one suffices). The tree can nest up to five levels deep, and a policy body is capped at 8 KiB, which is ample for real approval matrices.

POST /v1/saas-packages/019d.../approval-policies
Authorization: Bearer $TOKEN
Content-Type: application/json

{
  "category": "production_deployment",
  "name": "Production sign-off",
  "rules": {
    "operator": "AND",
    "conditions": [
      { "type": "role", "role_key": "senior_engineer", "required_count": 2 },
      { "type": "role", "role_key": "security_reviewer", "required_count": 1 }
    ]
  }
}

List the policies for a package with GET, and deactivate one with DELETE /approval-policies/:policyId.

Requesting, approving, and rejecting

The approval workflow is scoped to a release and a target environment. You request approval, approvers approve or reject, and you can check where the release stands against the policy at any time before you deploy.

ActionEndpointBody
Request approvalPOST /releases/:releaseId/request-approvalenvironment
ApprovePOST /releases/:releaseId/approveenvironment, optional comment
RejectPOST /releases/:releaseId/rejectenvironment, required reason
Check statusGET /releases/:releaseId/approval-status?environment=query only

The status check evaluates the active policy and reports which conditions are satisfied, so the go or no-go is visible before you act. A rejection requires a reason, and that reason is recorded so it is actionable.

POST /v1/saas-packages/019d.../releases/019e.../approve
Authorization: Bearer $TOKEN
Content-Type: application/json

{
  "environment": "production",
  "comment": "Reviewed the diff and the compliance check. Approved."
}

Why an approval cannot be reused or self-granted

Two properties make these approvals trustworthy in a way that email and chat sign-offs never are:

  • Bound to the exact release and environment. An approval is tied to a specific hash-verified snapshot and a specific environment. It cannot silently carry over to a different change or a different stage.
  • Separation of duties. The person who created a release cannot approve their own release for promotion. A different user must approve it. This is the four-eyes principle required by SOC 2 and ISO 27001, enforced by the system rather than by policy alone.
  • A rejection invalidates earlier approvals. If a release is rejected, approvals gathered before the rejection no longer count. The release must be re-approved cleanly, so a stale sign-off can never carry a change forward.
The builder creates Release v7, a document stamped with a snapshot hash. It reaches the production gate, whose production_deployment policy requires two senior engineers and one security reviewer to approve. Three distinct reviewers approve, each shown with a green check. The builder is refused self-approval, shown with a red cross and the note builder cannot approve their own release. If the release is rejected, a required reason is recorded and every prior approval is invalidated, turning from green to grey, so the release must be approved cleanly again.
An approval is bound to the exact snapshot and environment, the release creator cannot approve their own release, and a rejection invalidates every approval gathered before it.

Review in Context: The Conversation Trail

After this section you will be able to discuss a release where the release lives, with typed, threaded entries that stay attached to the exact snapshot. Instead of scattering review across chat and email, each release carries its own conversation. Every entry is typed so the trail reads as a structured review, not a chat log.

FieldRequiredMeaning
contentYesThe comment text, 1 to 5,000 characters.
comment_typeNoOne of general, bug, test_pass, test_fail, approval, rejection, task.
environmentNoThe environment the comment relates to.
parent_comment_idNoReply to another comment to build a thread.
POST /v1/saas-packages/019d.../releases/019e.../comments
Authorization: Bearer $TOKEN
Content-Type: application/json

{
  "content": "Pricing tier copy reviewed and correct for staging.",
  "comment_type": "test_pass",
  "environment": "staging"
}

List comments with GET, filtered by environment and comment type. The trail is part of the release’s record: corrections are new entries, never rewrites.

Progressive Rollout

After this section you will be able to release to production gradually and keep your hand on the controls the whole time. When you deploy, you choose how widely the release applies. A rollout plan turns a deployment into a controlled, reversible ramp instead of an all-at-once flip.

StrategyWhat it does
immediateApply the release to everyone at once.
targetedEnable the release for specific tenants first (up to 1,000 named tenants).
percentageApply the release to a set percentage of tenants.
progressiveRamp through a series of stages, each with a cumulative target percentage and a wait time before the next stage.

A progressive plan holds up to 20 stages, each with a target percentage from 1 to 100 and a wait time in hours. Stages advance automatically on schedule, or you can advance the next stage yourself. At any point you can pause, advance, or cancel, so if an early cohort looks wrong you stop the ramp immediately.

ControlEndpoint
Create a rollout planPOST /:packageId/rollouts
Inspect per-stage progressGET /rollouts/:rolloutId
Advance to the next stagePOST /rollouts/:rolloutId/advance
Pause the rampPOST /rollouts/:rolloutId/pause
Cancel the rampPOST /rollouts/:rolloutId/cancel

If a problem shows up mid-ramp, you are never stuck: pause or cancel the rollout, then roll back to a previous known-good snapshot as described next.

Rollback and Undeploy

After this section you will be able to return an environment to a known-good release in one action, and to remove a release from an environment entirely. Because snapshots are immutable, rollback is a safe operation: you are redeploying a state that already passed, not reconstructing it.

POST /v1/saas-packages/019d.../releases/019e.../rollback
Authorization: Bearer $TOKEN
Content-Type: application/json

{
  "environment": "production",
  "notes": "Regression observed in v7; returning to the prior known-good release."
}

Rollback re-activates the target release’s snapshot in the named environment. It restores the packaged configuration exactly, and it does not revert live customer data. It takes a single action and applies right away, and it is prominently recorded in the audit log and in the release’s tamper-evident chain.

To remove a release from an environment without replacing it with another, use undeploy:

POST /v1/saas-packages/019d.../releases/019e.../undeploy
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "environment": "staging", "notes": "Pulling this release from staging." }

Keep Building After You Ship: Import to Draft

After this section you will be able to continue building from exactly what you shipped. A finalized release can be loaded back into the package’s editable draft so its configuration becomes your new working baseline. This is the supported way to branch fresh work from a known release: ship, then pick up exactly where that release left off. The request requires the environment whose deployed release you are importing.

POST /v1/saas-packages/019d.../releases/019e.../import-to-draft
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "environment": "production" }

Compliance Checks and Audit Evidence

After this section you will be able to prove, on demand, that a change was authorized, tested, approved by someone other than its author, and deployed in order. Before a release is deployed to a target environment, you can run an automated compliance check. It runs nine checks mapped to industry control frameworks and writes the result as an immutable, hash-chained record. The overall result is passed only when no check fails; individual checks may pass, be skipped, or return a warning.

POST /v1/saas-packages/019d.../releases/019e.../compliance-check
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "target_environment": "production" }
CheckFrameworksValidates
Snapshot integritySOC 2 CC6.8The recomputed SHA-256 of the snapshot matches the stored hash, confirming no tampering since the snapshot was created.
Separation of duties (no self-approval)SOC 2 CC8.1, PCI DSS 6.5.4The release creator did not approve their own release for this environment.
Approval existsSOC 2 CC8.1At least one approval is recorded for this release and target environment.
Sequential promotionISO 27001 A.8.31The prerequisite environment is deployed (pre-production requires staging; production requires pre-production).
Privacy policy presenceGDPR Article 25The snapshot contains a non-empty privacy policy URL (a warning if missing).
No test or debug data in productionPCI DSS 6.5.6Production snapshots are scanned for test and debug indicators (skipped for non-production targets).
Data bundle presenceSOC 2 CC8.1The snapshot includes a data bundle with an integrity hash.
App configuration presenceSOC 2 CC8.1The snapshot includes at least one application configuration.
Deployment audit-chain integritySOC 2 CC7.1, HIPAA 164.312(b)The deployment-history hash chain has no sequence gaps.

This is exactly the evidence a Type II auditor samples. When an auditor pulls a change and traces it from request to deployment, the release carries its own linked evidence: the snapshot and its hash, the approvals with timestamps, the typed review trail, and the promotion history. The sequential gate plus timestamped approvals are what prevent the classic finding of a deployment that predates its approval.

The Tamper-Evident Audit Trail

After this section you will be able to answer, for a security review, exactly why nobody, including an administrator, can rewrite release history. Every release operation (create, deploy, approve, reject, rollback, and compliance check) is written to an append-only, cryptographically chained integrity log. Each entry is bound to the one before it, so the log forms a continuous chain.

  • Snapshot hash. A SHA-256 hash over the full snapshot contents is stored on the release record, so anyone can confirm the snapshot has not changed.
  • Integrity chain. Each record is cryptographically bound to the previous one, so the log cannot be altered after the fact without breaking the chain.
  • Detectable tampering. The chain can be re-walked and re-verified to confirm no record was modified, deleted, inserted, or reordered.
  • Signed with a protected key. The integrity log is signed with a key held on the server that is never exposed to clients.

In practice this means the audit trail is not something an administrator can quietly edit. Corrections are new recorded events, never rewrites of old ones. These records are retained as immutable audit evidence; for the retention schedule and the platform’s own attestations, see Security & Compliance and the Trust Center.

Who Can Do What

After this section you will be able to decide who in your organization can build, approve, deploy, and roll back. Release management follows the same role and permission model as the rest of the workspace. You grant each capability to the roles that should hold it, so builders build, reviewers review, and only the right people deploy to production.

CapabilityPermission
Create and update releasessaas_release.create, saas_release.update
View releases, history, and statussaas_release.view
Deploy and undeploy, manage rolloutssaas_release.deploy
Approve or reject a releasesaas_release.approve
Roll back an environmentsaas_release.rollback
Run compliance checkssaas_release.compliance
Add and read review commentssaas_release.comment, saas_release.view
Import a release back to draftsaas_release.import
Manage approval policiesapproval_policy.create, approval_policy.view, approval_policy.delete

Everything is scoped to your organization: a request that crosses the organization boundary is refused. See Roles & Permissions to assign these capabilities to roles.

Frequently Asked Questions

When I cut a release, what actually gets captured?
The entire package: screens, entities, workflows, roles and permissions, pricing and package configuration, AI skills, connector configs, views, app configs, seed data, and data bundles. It is captured deterministically and hash-verified. What is not captured is your customers’ live tenant data, so promotion and rollback change the app, never the records your users created inside it.

How do I see what changed between two versions?
Use the diff view, which compares the two snapshots and lists what was added, changed, and removed. Version numbers are assigned automatically as sequential integers, so there is no ambiguity about which is newer.

Will the approval process slow down my dev iteration?
No. Deploying to development skips the approval quorum and the separation-of-duties check so you can iterate fast. The gating applies to staging, pre-production, and production.

Can stage-skipping actually be blocked, or is it just a convention?
It is enforced. Pre-production requires an active staging deployment, and production requires an active pre-production deployment. Attempting to skip a stage is refused.

Is my approval bound to this exact version, or could it be reused on a later change?
It is bound to that specific hash-verified snapshot and that specific environment. It cannot transfer to a different change or stage, and a later rejection invalidates approvals gathered before it.

Can I approve my own change?
No. The person who creates a release cannot approve it for promotion; a different user must approve. This is enforced by the system, not left to policy.

How fast is rollback, and is it lossless?
Rollback is a single action that re-activates a known-good prior snapshot right away. It restores the packaged configuration exactly. It does not revert live customer data.

Can I keep editing after I ship?
Yes. Import a shipped release back into your working draft with import-to-draft, and it becomes your new baseline so you continue from exactly what shipped.

Is the audit log truly immutable and tamper-evident?
Yes. It is append-only and hash-chained, and modified, deleted, inserted, or reordered entries are detectable when the chain is re-walked. No user or administrator can rewrite history; corrections are new events.

Which controls map to which framework?
The nine compliance checks carry explicit mappings to SOC 2, ISO 27001, PCI DSS, HIPAA, and GDPR, listed in the compliance-checks table above, so you can hand the mapping to your auditor.

API Reference

Release endpoints are scoped to a SaaS package (:packageId).

  • GET /v1/saas-packages/:packageId/releases: list releases (filter by status).
  • POST /v1/saas-packages/:packageId/releases: create a release snapshot.
  • GET /v1/saas-packages/:packageId/releases/:releaseId: get release details and snapshot contents.
  • GET /v1/saas-packages/:packageId/releases/diff?from=&to=: diff two releases.
  • GET /v1/saas-packages/:packageId/releases/:releaseId/items: list version-pinned manifest items.
  • PATCH /v1/saas-packages/:packageId/releases/:releaseId/status: set release status.
  • POST /v1/saas-packages/:packageId/releases/:releaseId/deploy: deploy to an environment.
  • POST /v1/saas-packages/:packageId/releases/:releaseId/undeploy: remove from an environment.
  • POST /v1/saas-packages/:packageId/releases/:releaseId/request-approval: request approval.
  • POST /v1/saas-packages/:packageId/releases/:releaseId/approve: approve for an environment.
  • POST /v1/saas-packages/:packageId/releases/:releaseId/reject: reject for an environment.
  • GET /v1/saas-packages/:packageId/releases/:releaseId/approval-status?environment=: evaluate policy status.
  • POST /v1/saas-packages/:packageId/releases/:releaseId/compliance-check: run the compliance checks.
  • POST /v1/saas-packages/:packageId/releases/:releaseId/rollback: roll an environment back to this release.
  • POST /v1/saas-packages/:packageId/releases/:releaseId/import-to-draft: import back into the editable draft.
  • GET / POST /v1/saas-packages/:packageId/releases/:releaseId/comments: list or add review comments.
  • GET /v1/saas-packages/:packageId/environments: current deployment per environment.
  • GET /v1/saas-packages/:packageId/environments/history: promotion history.
  • GET / POST /v1/saas-packages/:packageId/approval-policies: list or create approval policies.
  • DELETE /v1/saas-packages/:packageId/approval-policies/:policyId: deactivate a policy.
  • POST /v1/saas-packages/:packageId/rollouts, GET /rollouts/:rolloutId, and advance / pause / cancel: manage progressive rollout.

Related reading

See the SaaS Builder API for complete request and response documentation.