Services

When you deploy backend code to Forte, it becomes a Service: a containerized app that Forte hosts, scales, and monitors.

How services work

To call a Service, send an HTTP request to its Forte endpoint. The Forte API gateway authenticates the User, routes the request to your Service over a private network, and records request logs and metrics.

Forte sits in front of every Service, so authentication, rate limiting, and DDoS protection happen before a request reaches your code:

Client
Browser or mobile app
Forte Gateway
Authentication · Rate limiting · DDoS protection · Logging
Your Service
Your code, autoscaled

Supported languages and frameworks

Forte detects common backend languages and frameworks from your repository and builds a container image. You don't need to provide a Dockerfile for supported stacks.

If your repository already includes a Dockerfile, Forte uses it as-is, so any language or framework that runs in a container is supported. Either way, Forte discovers the port your app listens on and runs it behind the gateway with autoscaling, TLS, and observability.

Service endpoint

Every service deployed on Forte gets a unique HTTPS endpoint on the tryforte.dev domain. This is your service's invocation URL — the address your frontend, mobile app, or any client uses to send requests to your backend.

Forte creates this permanent endpoint with the service. It stays the same across deployments, so you can use it as your backend URL.

Custom domains

Custom domains are available. Add one from the service's page in the Forte Console, then point your DNS at the domains.tryforte.dev endpoint shown there (a CNAME). Forte provisions and renews the TLS certificate for you. Your generated tryforte.dev endpoint keeps working alongside your custom domain.

Built-in tools

Forte includes tools for hosting and maintaining your services:

  • Request debugging: Forte records each request and links it to related app logs.
  • Automatic builds: Forte detects your code's language and framework. It uses your Dockerfile or generates one when needed.
  • Integrated monitoring: Forte provides a dashboard for your performance metrics and sends alerts when it detects errors or performance regressions.

Environment variables and service tokens

Every service deployed on Forte automatically receives three environment variables at runtime:

VariableDescription
FORTE_PROJECT_IDThe ID of the project this service belongs to
FORTE_SERVICE_IDThe ID of this service
FORTE_API_TOKENA Bearer token scoped to this service's project

Your service can use FORTE_API_TOKEN to call Forte's server-side API — for example, to manage users, read project data, or interact with other resources within the same project. Include it as a Bearer token in your requests:

Server-side (API key):

bash
curl -H "Authorization: Bearer $FORTE_API_TOKEN" \
  https://api.tryforte.dev/api/v1/projects/$FORTE_PROJECT_ID/users

If you use the Forte runtime SDKs for TypeScript, Java, or Python, credentials are loaded automatically from these environment variables — no manual configuration needed.

Project-scoped permissions

The service token can only access resources within its own project. It cannot access other projects or perform account-level operations.

Server-only credential

FORTE_API_TOKEN is a server-side secret. Never expose it to a browser or commit it to your repository. To let your signed-in users call Forte directly from your frontend, use Forte's client-side API instead — it uses the user's session cookie, not the project API key.

The FORTE_ prefix is reserved — you cannot create custom environment variables that start with FORTE_.

Build triggers

Each service deploys from a GitHub repository. Choose how new deployments are triggered:

  • On every push to branch — every commit to the configured branch builds and deploys automatically. Best for staging and continuous-deployment workflows.
  • On GitHub release published — only deploys when a new GitHub release is published. Best for production services that should roll forward on tagged releases.

You can also deploy any commit manually. See Deploying services for instructions.

Scaling and background work

Forte automatically scales Service compute down when your code isn't actively handling web requests.

Because of this, background work scheduled inside your service is not reliable. Timers, cron loops, polling threads, and in-process schedulers (for example a setInterval or a scheduler library running in your app) can be paused or stopped when your service scales down, and may never fire while your service is idle. Don't rely on your service staying warm to run work on a schedule.

Use Actions for scheduled work

To run work on a schedule or asynchronously, use actions instead — Forte calls a path on your service on a cron schedule or at a one-time future moment, so the work runs even when your service isn't handling traffic. See Create your first action to set one up.

Pausing a service

You can pause a service from its console page. Pausing stops all the service's provisioned compute — and with it the service's compute billing — until you resume it.

While a service is paused:

  • Requests are rejected. The service's endpoint returns 503 with error code SERVICE_PAUSED. Requests are rejected before they reach your app, so they don't appear in request logs or metrics.
  • Compute billing stops. You are not billed the base or active compute rates while the service is paused. See Pricing.
  • GitHub-triggered builds are skipped. A push (or published release) to the service's repository does not build, deploy, or resume it. The build is recorded in the deployment history and immediately cancelled with a "Build skipped" message, so you can see which commits were skipped — and skipped builds are free. To deploy the latest code, resume the service and retry the build.
  • Manually triggered deployments still run. A deployment you start yourself — retrying a build from the console or saving a configuration change that triggers a rebuild — builds and deploys normally, and automatically resumes the service.

The service's endpoint doesn't change while paused — resuming brings it back online at the same URL. You can't pause a service while a build is in progress.

Pause and resume are also available on the server-side API as forte.projects.pauseService and forte.projects.resumeService.

Authentication path exclusions

By default, every request to your service is authenticated — Forte verifies the user's identity before forwarding the request to your app. If some routes need to be publicly accessible (health checks, webhooks, public APIs), configure authentication path exclusions to bypass user authentication for specific paths.

Pattern syntax

Path exclusions use Ant-style patterns, supporting three wildcards:

TokenMeaningExample
?Matches exactly one character/api/v?/status matches /api/v1/status
*Matches zero or more characters within a single path segment/api/*/health matches /api/orders/health
**Matches zero or more path segments/api/public/** matches /api/public/foo/bar/baz

Common examples

PatternMatchesDoes not match
/health/health/health/deep
/api/public/**/api/public, /api/public/users, /api/public/a/b/c/api/private
/webhooks/*/callback/webhooks/stripe/callback/webhooks/stripe/callback/retry
/**/*.css/styles/main.css, /assets/fonts/icon.css/styles/main.js

Testing your patterns

When editing a service in the console, use the built-in path tester to verify your patterns before saving. Enter a request path and click Test to see whether it would be excluded from authentication and which pattern matched.

Use with caution

Excluding paths from authentication means those requests aren't tied to a user identity. This limits Forte's per-user observability, rate limiting, and abuse protection on those routes. Keep exclusions few, and use them only for genuinely public endpoints.

CORS preflight

Browser CORS preflight requests (OPTIONS) are automatically forwarded to your service without Forte authentication. This lets your service own its CORS policy — set the Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers response headers from your code, and Forte returns them to the browser unchanged.

This applies only to OPTIONS. Every other method — including HEAD — is still authenticated like a normal request. (Browsers send credentials on HEAD the same way they do on GET, so treating HEAD as auth-exempt would let unauthenticated callers probe response headers on protected paths.)

You do not need to add OPTIONS paths to your authentication path exclusions — preflight is exempt platform-wide.

First-party auth routes (/_forte)

Every service reserves a /_forte path prefix that forwards to Forte's user-authentication routes. It exists so your frontend can set the Forte-User-Session-Token cookie on your own domain instead of Forte's — a first-party cookie that browsers won't block. Point the SDK's baseUrl at your service's /_forte prefix when you need cookies to match your domain:

ts
import { ForteClient } from "@forteplatforms/sdk";
 
// forte.users.* calls travel through /_forte on your own domain,
// so the session cookie is scoped to your site.
const forte = new ForteClient({ baseUrl: "https://yourapp.com/_forte" });

Only end-user (forte.users.*) routes are reachable through /_forte, and requests through it are handled by Forte before they reach your service (so they don't appear in your request logs or metrics). See SDKs → First-party cookies via /_forte for the full details.

Response streaming

The gateway streams your service's response back to the caller as your service produces it, instead of waiting for the full body. If your service writes and flushes output incrementally, each chunk reaches the client the moment you flush it.

This means Server-Sent Events (SSE) and chunked responses work through the gateway with no configuration. Token-by-token output from a model endpoint is forwarded as your service generates it, and large file downloads stream straight through without the gateway holding them in full.

Streaming applies to the response your service returns. Request bodies are received in full before the request is forwarded to your service.

Requests have a 120-second timeout

Every request to a service must complete within 120 seconds, measured from when the gateway receives the request to when your service finishes writing the response. Streaming suits responses that finish inside that window, such as progressive rendering or model output — not connections held open indefinitely, like an event stream that never closes. If your service hasn't started responding when the limit is reached, the gateway returns a 504.

Search

Search documentation and console pages