Say you're deploying Weekly Brief, a reports app whose Next.js frontend, Node.js API, and shared request types live in one repository. Both apps build on your laptop from the repository root. When you point the hosted API build at apps/api, the build fails because the shared package lives outside the folder the host can see.
When you deploy a monorepo, write down where each app builds and runs, then check how it gets shared code and settings. Use the same plan to decide where database changes run and which app releases need to work with each change.
Draw the parts that will run
In this hypothetical app, the browser calls a Node.js API, which reads and writes Postgres with credentials that stay on the server. The repository keeps the two apps, their shared types, and the database migrations in separate folders.
apps/web Next.js frontend
apps/api Node.js API
packages/types Shared request types
db/migrations Versioned database changesShared types help the frontend and API agree on request fields. Since a caller can send a request without using the frontend, the API also checks that the incoming data is valid and that the caller can access the report.
Write down each app's build command, start command, and needed files. Note which settings belong in browser code and which must stay on the server. This small map helps a teammate reproduce the hosted build without relying on files left over from your laptop.
Give each build the files it needs
A container build can use files from a directory called the build context. If the context is apps/api, its Dockerfile can't copy ../../packages/types because that directory sits outside the context. The same Dockerfile can have access to different files depending on where you start the build.
Weekly Brief can publish the shared types as a package so each app installs a version it can fetch. If the host supports a build context that includes the shared source and root package files, the team can also build with those files directly. Check which approach your host supports before choosing a base directory.
On Forte, the selected base directory becomes the container build context. A Service set to apps/api sees that directory as its build root. Its Dockerfile and copy paths must fit that boundary. Websites have the same base-directory concern. Forte monorepo guide
Check lockfiles and workspace settings as part of this choice. If the install command expects a lockfile at the repository root, giving it only apps/api leaves an input missing. Pin the versions you ship so rebuilding an older release doesn't quietly pick up changed shared code.
Check when Next.js reads each setting
The browser needs Weekly Brief's public API address to send requests. The API needs a private database URL to save reports. Both values can come from environment settings, so check where each app reads them before you build.
Next.js can include public values in the browser bundle at build time. If you build with a staging API address and later promote that same output, it can keep calling staging. Read the self-hosting guidance for your app's version and check where each value is read. Next.js self-hosting guide
After deployment, inspect a request from the browser. Check its destination and the release that handles it. This verifies the actual setting the built app uses without printing server secrets.
Keep database credentials and payment secret keys out of public variables. A value included in browser code is available to the person using that browser.
Choose one step to change the database
The API and frontend may deploy at different times. Two API versions may also run during a rollout. Plan database changes so those versions can work together.
Give migrations one owner in the release process. Avoid making every new instance race to apply the same change when it starts. Record the schema version the release expects and how you will apply it.
Suppose Weekly Brief needs a new report status. Add a field that old rows can leave empty, deploy code that understands both forms, and fill old rows in bounded batches. Remove the old form only after active code no longer needs it. This lets you return to a prior release without immediately breaking its database reads.
Test an old report and a new report after the change. Try restoring synthetic data before any change that could damage rows. A code rollback and a data restore solve different problems, so keep both paths clear.
Deploy each link and test a report
Deploy the API first and call its health route to see whether the process can answer. Then use a synthetic account to save a report and read it back, which shows whether the API can use the database as well.
Next, deploy the frontend with the intended API address. Sign in through the browser, save a report, and reopen it. Check errors and cross-origin settings if the website and API use different addresses.
Set database pool limits based on how many API instances may run at the same time. Four instances with a pool of ten each can try to open forty connections. Leave room for migrations and support, and measure how many connections the app uses before raising the limits.
Map the repository to Forte resources
Create a Project and connect the GitHub repository. Deploy apps/api as a Service and apps/web as a Website, using a base directory that fits each app's build plan. Check the monorepo steps before relying on shared root files.
Create Postgres in the Project and connect it to the API. Check that the driver reads the variable names and connection-string format Forte injects when it connects the database and redeploys the Service. Postgres is Open Beta. The shared tier offers 1–10 GB of storage and daily backups, with restores through Support. Dedicated Postgres with point-in-time restore is closed alpha. Forte databases
Run the report journey after both resources deploy. Save the API release, frontend release, and schema version with the result. Those three references make the next failed report much easier to place.