Introduction

Coupling a UI and an API in one deploy path is convenient until one of them needs to move faster than the other. A directory product made that tension visible: the interface had to stay usable while the data layer and endpoints kept changing.

This article covers the split I used: a dedicated frontend repository and a dedicated API, each deployed independently, with a contract between them instead of a shared codebase.

The Problem

When the interface and the data layer ship together, a copy change and a schema change become the same release. That slows both sides. It also makes failures harder to isolate: a blank page could be a UI bug or an API timeout.

The constraint was a public product that still needed to evolve. A monolith would have been simpler to start. It would not have stayed simple once the API needed its own environment, validation, and clients.

Approach

The frontend owns presentation, routing, and client-side fetching. The API owns data, validation, and persistence. They meet at HTTP, not at shared folders.

Each side has its own repository and its own production URL. That makes the contract explicit: if the API shape changes, the frontend has to change against a versioned endpoint, not against an internal import.

Implementation

The frontend lives in `BeTainos-directory-frontend` and deploys as its own Vercel project. The API lives in `dcl_api` and deploys separately. The UI does not bundle server secrets; it calls the public API.

That split also made local work clearer. The interface can be developed against a deployed API. The API can be tested without running the full UI. The cost is contract discipline: breaking response shapes become visible immediately.

Challenges & Trade-offs

Two repositories mean two deploy pipelines and two places to look when something fails. That is real overhead. I accepted it because the alternative was a single release that mixed unrelated risk.

A BFF in the frontend would have hidden the API, but it would also have pulled server concerns back into the UI project. For this product, a public API was the clearer boundary.

Impact

Results / Impact

The split produced a chain of evidence that is easy to inspect: a live interface, a live API, and two repositories that show how the work is actually organized.

2 repos

Frontend and API versioned independently

Live UI

Public frontend on Vercel

Live API

Public API on its own deploy

  • UI and API can ship on different schedules.
  • Production failures are easier to attribute to the interface or the data layer.
  • The HTTP contract is the documentation, not a shared internal module.

What I Learned

The contract is the product. If response shapes are sloppy, the split creates more work than it saves.

I would define a small public schema earlier, even before the UI is pretty. The frontend should consume a stable surface, not whatever the API happened to return that week.

Future Improvements

Typed client generation and explicit API versioning would make the boundary safer as more consumers appear. The current split is enough for one interface. It is not yet a platform.