DEV Community

Cover image for Integration Is the Product: Platform Engineering for Fast Frontend Teams
Piyush Chauhan
Piyush Chauhan

Posted on

Integration Is the Product: Platform Engineering for Fast Frontend Teams

How local composition, exact artifacts, and versioned releases turn a dependency queue into continuous feedback.

A visual overview of the four feedback loops: local workbench, real product shell, PR preview, and versioned release.

The useful measure of team autonomy is not “can it publish?” It is “how quickly can the team see its exact change running in a realistic product?”

A frontend package can compile, test, and publish successfully—and still break when the product shell owns routing, authentication, server-side rendering (SSR), hydration, global styles, middleware, or a singleton dependency such as React.

I learned this through a familiar local loop:

build package → pnpm pack → edit the shell's package.json → install → run → discover → repeat
Enter fullscreen mode Exit fullscreen mode

That loop proves the product boundary matters. It is also a warning: integration has become manual, temporary state leaks into committed files, and every cross-team change waits for the central application to catch up.

The answer is not “never integrate” or “put everything in a monorepo.” The answer is to make integration a self-service product capability: composable locally, verified as an artifact, previewable in a pinned product, and promotable as an immutable release.

The model in one picture

Four feedback loops progress from a fast local workbench to a real shell, an exact-artifact preview, and an immutable release.

Each loop answers a different question. Do not make the slowest one the default.

Loop Question it answers Default use Evidence it produces
1. Domain workbench Does the domain feature behave correctly? Daily implementation Fast, deterministic UI and contract feedback
2. Local product composition Does my source work in the real shell? Host-boundary changes Routing, auth, SSR, hydration, styling feedback
3. PR product preview Does the artifact I intend to ship work in a clean product? Before merge A reviewable URL using exact candidate bytes
4. Versioned release Is this selected composition healthy under shared and production conditions? Promotion Canary and operational evidence

The important design rule:

A failure found in an outer loop should improve the cheapest inner loop that can catch it next time.

Some failures—real traffic, irreversible migrations, external side effects—belong in the outer loop. Pretending every risk can move left makes local feedback less trustworthy, not more.

A concrete example: the Booking module

Assume a Booking frontend module mounted in a product shell. It calls Hotel APIs, participates in auth and routing, emits booking events, and server-renders UI.

Here are the four boundaries where its “green” isolated build can still fail:

┌──────────────────┐    ┌────────────────────────┐
│ Booking package  │───▶│ Product shell          │
│ exports, assets, │    │ routing, auth, SSR,    │
│ peer dependencies│    │ hydration, CSS         │
└────────┬─────────┘    └──────────┬─────────────┘
         │                         │
         ▼                         ▼
┌──────────────────┐    ┌────────────────────────┐
│ Domain contracts │    │ Environment and data   │
│ Hotel API/events │    │ pinned versions, known │
│ errors, timing   │    │ scenarios, replayable  │
└──────────────────┘    └────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

1. Build and artifact boundary

Local linking can succeed while the published tarball omits types, CSS, assets, compiled files, or an export-map entry. It can also hide bad peer-dependency resolution.

A particularly expensive frontend failure is a duplicate singleton: Booking bundles React or framework context while the shell expects to own it. Hooks, contexts, or hydration then fail only in the composed application.

Design consequence: support fast local source overrides and install the packed artifact into a clean shell in CI. Neither replaces the other.

2. Platform and runtime boundary

A mini-shell is valuable, but it is not the product. The real shell may resolve auth asynchronously, evaluate flags on the server, enforce CSP, select locale, apply global CSS, and hydrate browser markup.

A synchronous fake user can hide a lifecycle race. A window access can pass locally and fail during SSR. A global selector can quietly override the product header.

Design consequence: teams need an easy route into the real shell before release—not a handoff to another team.

3. Domain contract boundary

Types alone are not contracts. A Hotel response can make a field optional; an event can be duplicated; a shared package can preserve its type while changing runtime behavior.

Design consequence: contracts need examples for absence, errors, timeout, compatibility, and delivery semantics. Providers own valid fakes; consumers own the assumptions they make.

4. Environment and data boundary

A shared environment called dev is usually a location, not a reproducible state. It may contain yesterday’s Hotel build, today’s Payment candidate, mutable test accounts, and an unannounced shell change.

Design consequence: pin composition and provide named, deterministic data scenarios. A passing result should be attributable; a failure should be replayable.

The paved road: two local modes, one composition contract

The productive workflow is not “fake everything” versus “run the whole company.” It offers two intentionally different local modes.

Mode A: domain workbench

The workbench mounts local Booking with the production rendering mode, design system, route contract, and named auth, flag, and locale scenarios. Hotel and Payment provide provider-owned fakes; inexpensive, behaviorally important infrastructure can run locally.

platform dev
Enter fullscreen mode Exit fullscreen mode

Use it for focused work. It should be fast, deterministic, usable offline where practical, and let an engineer select success, absence, timeout, error, and authorization states in one command.

Mode B: real-shell composition

The real product shell runs with released dependencies while the developer substitutes only local Booking source and gets HMR.

platform dev --composition=integration-stable
Enter fullscreen mode Exit fullscreen mode

Use it when the change touches routing, auth lifecycle, SSR/hydration, global CSS, middleware, or framework ownership. It removes the pnpm pack / edit-manifest / reinstall loop without claiming to prove the tarball.

A resolved composition makes every local override, remote dependency, and scenario visible.

Both modes resolve the same composition contract. The interface can be a CLI, package-manager feature, dev server, container stack, or managed environment; the durable part is the input and output:

composition: integration-stable@sha256:8f1e...
shell: product-shell@13.2.1
modules:
  booking:
    mode: local-source
    path: ../booking
    watch: true
  hotel:
    mode: integration-stable
    version: 5.8.2
  payment:
    mode: fake
    scenario: authorized
scenarios:
  auth: signed-in-customer
  locale: en-GB
data:
  booking: local-isolated
Enter fullscreen mode Exit fullscreen mode

A good platform dev command does four things before it starts:

  1. Resolves peer, shell-API, rendering-mode, and contract compatibility.
  2. Leaves the application’s normal package.json and lockfile untouched.
  3. Watches only explicit local overrides; released components remain immutable.
  4. Prints the resolved versions, modes, paths, scenario IDs, and manifest digest.

That last point matters. “Works on my machine” is useful only when “it” has an identity another developer or CI job can reproduce.

Useful companion commands are straightforward:

platform preview  # create or show this change's pinned preview
platform trace    # inspect correlated diagnostics
platform doctor   # explain peers, credentials, ports, versions, dependencies
platform reset    # remove generated state; never normal project files
Enter fullscreen mode Exit fullscreen mode

Let contracts unblock implementation—not conversation

Composition accelerates feedback after code exists. Contracts solve the earlier scheduling problem: how can Booking start when Hotel is not finished?

The teams still need to agree on meaning. The goal is to turn that agreement into a versioned candidate someone can consume immediately.

For a cancellable reservation hold, the sequence is:

  1. Agree on the smallest useful contract. Request, response, errors, idempotency, timeout expectations, and representative examples.
  2. Publish a provider-owned candidate. Hotel ships the contract plus valid fixtures, fake adapter, or mock server under an immutable candidate ID.
  3. Implement the consumer against it. Booking exercises success, absence, timeout/error, and compatibility scenarios in the workbench.
  4. Verify the provider against the same agreement. Hotel’s CI verifies the implementation. Consumer-driven contracts can run concrete consumer expectations before merge; Pact is one option.
  5. Compose both candidates. The preview pins Booking and Hotel candidates for product-level review.
  6. Keep a declared compatibility window. Support current and previous versions unless an exception is explicit and time-bounded.
semantic decision
        │
        ▼
provider contract candidate ──────▶ consumer implementation
        │                                      │
        └──── provider verification ◀──────────┘
                         │
                         ▼
               pinned combined preview
Enter fullscreen mode Exit fullscreen mode

This separates a necessary semantic dependency from an avoidable implementation dependency. Contract verification does not prove assembled-product behavior, so the combined preview remains necessary.

Test the bytes you will release

Source composition is for speed. Artifact verification is for release confidence.

Before merge, CI should:

build once → pack once → attach commit and provenance → clean install into pinned shell → test → preview
Enter fullscreen mode Exit fullscreen mode

For a Node package, pnpm pack produces the tarball under test. The clean shell install should verify exports, included files, types, assets, lifecycle behavior, package metadata, SSR/hydration where relevant, and only the critical product journeys affected by the module.

The artifact that passes is the artifact that moves forward. Rebuilding for staging or production invalidates prior evidence.

The shell owns singleton dependencies such as React, framework runtimes, and shared contexts. Modules declare supported ranges through peerDependencies rather than bundling private copies. A compatibility manifest adds constraints package resolution cannot express—such as supported shell APIs, rendering modes, or contract generations—and fails an invalid composition with an explanation before it runs.

Provenance answers a different question: which source revision and CI build produced these tested bytes? It complements, rather than replaces, compatibility testing.

Preview a product, not an isolated copy of the company

A PR preview should be a hybrid composition:

  • dedicate the changed Booking candidate and shell where needed;
  • reuse known-stable Hotel, Payment, and other remote services;
  • pin every reused version;
  • expose the final composition and artifact IDs in the preview.

This gives QA, design, and product a reviewable URL without creating a full company clone for every pull request. It catches artifact omissions, clean-install failures, selected cross-domain behavior, and visual product issues. It still has bounded data, traffic, scale, and external integrations—so it is strong evidence, not a production guarantee.

GitOps gives promotion a memory

A composition is already declarative, so GitOps is useful connective tissue between verified bytes and running environments. It does not “solve integration”; it records, applies, and reconciles a selected product state.

composition: booking-canary-2026-09-12
shell: product-shell@13.2.1
components:
  booking:
    artifact: registry.example/booking@sha256:4d8c...
    version: 7.5.0
    sourceCommit: 91ac...
    buildProvenance: attestations/booking/4d8c...
  hotel:
    artifact: registry.example/hotel@sha256:70be...
    version: 5.8.2
Enter fullscreen mode Exit fullscreen mode
candidate artifact → composition-manifest PR → verification + preview
    → merge → reconciled environment → canary → manifest revert if unhealthy
Enter fullscreen mode Exit fullscreen mode

This aligns with the OpenGitOps principles: desired state is declarative, versioned and immutable, automatically pulled, and continuously reconciled.

Keep environment semantics distinct:

Environment Purpose What may change it?
integration-latest Early compatibility signal from accepted updates Accepted component updates
integration-stable Dependable baseline for local hybrid development Deliberate known-compatible promotion
staging / release candidate Release evidence Deliberately selected manifest only
production Real customer and traffic evidence Canary promotion of a reviewed manifest

Routine deployments must not mutate staging. Otherwise it becomes contested shared workspace exactly when it needs to represent a release candidate.

A manifest revert restores the prior artifact digest. It cannot reverse destructive migrations or external side effects, so every module still needs a forward- and backward-compatible migration strategy.

Make failure attributable in one screen

Pinning versions is necessary but incomplete. Reproducibility also needs data and diagnostics.

A provisioned Booking scenario should have a testRunId, TTL, and cleanup policy. Records across Booking, Hotel, and Payment carry that identifier where permitted. Stable fixtures are immutable or automatically reset; tests needing mutation receive isolated data.

Requests and events should propagate trace and request IDs plus:

module version · product composition ID · contract version · testRunId
Enter fullscreen mode Exit fullscreen mode

OpenTelemetry provides the trace and context-propagation model. Adding composition context makes a trace actionable integration evidence.

A failed Booking request should answer:

  • Which Booking artifact and product composition handled it?
  • Which Hotel contract and service version were selected?
  • Which test scenario supplied the data?
  • Where did time or failure enter the trace?
  • Which team owns the failing capability and what changed last?

Ownership then follows the boundary: Booking triages a failure in its artifact; Hotel owns a published-contract violation; the platform team owns a composition engine rejection of a valid declared configuration. A bare failure routed to a team channel recreates the integration queue.

Start small: improve one developer journey

Do not begin by building a universal portal. Begin with the most painful edit-to-integrated-feedback loop and give it a measurable exit condition.

Stage Deliverable Exit condition
1. Make composition explicit Pinned shell/module versions, clean artifact install Any authorized engineer can reproduce a candidate from clean state without editing package.json.
2. Shorten local feedback Workbench, named scenarios, real-shell local overrides One command reaches a usable shell while the normal lockfile remains unchanged.
3. Move compatibility before merge Candidate contracts, packed-artifact CI, hybrid preview CI installs exact candidates into a clean pinned composition and reviewers can identify every changed/reused component.
4. Close the production loop GitOps manifests, canary, trace metadata, ownership routing The PR-tested artifact reaches canary/production unchanged and a safe revert restores the prior compatible version.

Measure the wait, not the tooling:

  • median edit-to-feedback time, separately for workbench and real shell;
  • percentage of PRs verified with the exact artifact later promoted;
  • local composition startup success rate, not just process starts;
  • preview request-to-ready and recovery time;
  • failures found before versus after merge, classified by boundary;
  • dependency-update lead time and blocked days caused by cross-team dependencies;
  • deployment failure/recovery outcomes and observed developer task success.

DORA’s delivery metrics are useful alongside these leading indicators. Do not turn them into a cross-team leaderboard: trends for one product journey reveal more than a blended organizational number.

Integration is the platform product

A weak platform makes teams publishable, then centralizes the moment of truth. A healthy platform makes the product boundary continuously available to the team changing it.

For Booking, that means one connected path:

local source in real shell
  → exact packed candidate in clean CI
  → pinned PR preview
  → reviewed composition manifest
  → canary with traceable identity
  → manifest revert when healthy evidence disappears
Enter fullscreen mode Exit fullscreen mode

Packages, separate repositories, and independent releases can all support this model. The decisive capability is faster, self-service feedback at progressively realistic levels—not the repository topology or a portal.

Integration is not the gate after development. Integration is the product the platform team provides.

References

  1. CNCF Platforms White Paper
  2. DORA: Platform engineering capability
  3. DORA: Software delivery performance metrics
  4. OpenGitOps principles v1.0.0
  5. Pact introduction
  6. pnpm pack documentation
  7. SLSA provenance
  8. OpenTelemetry trace concepts

Top comments (0)