A serverless API endpoint is best when one HTTP request maps to a bounded unit of work. An App Platform web service is better when the application itself needs to remain running as a persistent process with a broader routing, deployment, and service lifecycle.
Both can expose HTTPS APIs. Both can scale. Both can run familiar frameworks. The real difference is what your team is deploying: one independently triggered HTTP workload, or an application service that stays available as a running process.
For small teams, this distinction prevents two common mistakes. The first is turning an entire web application into many Functions even though its routes, middleware, background processes, and deployment lifecycle belong together. The second is keeping a full app service running only to serve one occasional webhook or callback endpoint.
At Raff, we treat the decision as an HTTP runtime question. Use Raff Functions when the endpoint should start from demand and finish independently. Use Raff Apps when the HTTP surface belongs to a persistent application service with a managed build, deploy, revision, and service lifecycle.
Function URLs and App Platform APIs expose HTTP differently
A Function URL maps HTTP traffic directly to function execution.
Client ↓ HTTPS Function URL ↓ Function invocation ↓ Response
An App Platform API runs as part of a persistent web-service process:
Client ↓ HTTPS web service ↓ Running app process ↓ Router / middleware / application routes ↓ Response
The client can see a normal HTTPS API in both cases. The difference is the runtime lifecycle behind it.
| Decision area | Function endpoint | App Platform web service |
|---|---|---|
| Deployment unit | Function or bounded handler | Application service |
| Process lifecycle | Demand-triggered execution | Long-running service process |
| Routing | Narrow function-owned HTTP surface | Broader application routing |
| Idle behavior | Designed to scale to zero | Platform service may also scale to zero, depending on configuration |
| Background processes | Separate functions/triggers | Workers, cron, and one-off services can live in same app project |
| Deployment workflow | Function deployment | Git/Docker/buildpack application deployment |
| Revisions/rollback | Function lifecycle | App-level immutable revisions and rollback |
| Best fit | Webhooks, callbacks, narrow APIs | Full web apps, multi-route APIs, application services |
A Function URL is not inherently simpler because it has fewer routes. An app service is not inherently heavier because it is persistent. The better model is the one whose lifecycle matches the application.
Function endpoints fit narrow, independently scalable HTTP work
Use a serverless API endpoint when one HTTP workload can stand on its own.
Good candidates include:
- payment or SaaS webhooks;
- OAuth or provider callbacks;
- low-traffic public endpoints;
- lightweight internal APIs;
- form handlers;
- status-update endpoints;
- endpoints that validate a request and create background work;
- isolated API routes with very different traffic from the main application;
- APIs that spend meaningful time idle.
A good function-shaped endpoint usually has:
- a clear request boundary;
- bounded execution;
- durable state outside the runtime;
- no requirement for one process to stay alive between requests;
- independent traffic or scaling characteristics.
For example:
Billing provider ↓ Webhook Function ↓ verify + store event ↓ acknowledge
That endpoint does not need the entire customer-facing application process just to receive an event.
Raff Functions currently gives each deployed HTTP Function a live HTTPS URL with automatic TLS. Standard handlers include Python FastAPI/ASGI, Node.js HTTP, JavaScript Web Fetch, TypeScript, and Go net/http, with a Dockerfile escape hatch for custom runtimes. Idle Functions can scale to zero and autoscale with load.
The broader Serverless APIs and Webhooks guide owns the architecture of HTTP Functions. This guide owns the decision about when that direct endpoint should remain a Function versus become part of a full application service.
App Platform APIs fit application-shaped HTTP surfaces
An App Platform web service is stronger when the API belongs to a larger application lifecycle.
Common signals include:
- many related routes;
- shared middleware across the API;
- a full framework application such as Django, FastAPI, Express, Rails, Laravel, or another long-running web service;
- shared in-process connection pools or caches;
- multiple application processes that deploy together;
- background workers tied to the same release;
- cron jobs tied to the same codebase;
- preview environments for pull requests;
- coordinated application revisions and rollback;
- persistent volumes or service bindings used by the application;
- a team that wants Git-based push-to-deploy across the whole service.
Raff Apps currently supports GitHub push-to-deploy, Dockerfiles, auto-buildpacks, full Docker Compose imports, immutable revisions, one-click rollback, preview environments, persistent volumes, and five service types: public web, private service, worker, cron, and one-off job.
That changes the operating unit. Instead of managing each endpoint as an independent function, the team deploys an application service and its related processes as one project.
If routes, middleware, workers, and releases change together, keeping them in one app-service lifecycle can be simpler than splitting them into many independently deployed Functions.
The existing Cloud VM vs App Platform guide owns the broader App Platform versus server-control decision. This page stays at the HTTP layer: direct Function endpoint versus managed application API.
Route count is a signal, not a hard threshold
Teams sometimes ask how many API routes justify moving from Functions to an App Platform.
There is no universal number.
Five completely independent webhook endpoints can remain clean as Functions. Three tightly coupled routes sharing complex middleware, sessions, common caches, and release behavior may already be easier as one application service.
Use coupling rather than raw route count:
| Question | Favors Function endpoints | Favors App Platform API |
|---|---|---|
| Do routes deploy independently? | Yes | No, they release together |
| Do routes share heavy middleware? | Little | Extensive |
| Do routes share one process-level runtime? | Not needed | Useful |
| Does each route have different traffic? | Often | Mostly similar |
| Are workers/cron part of same codebase? | Separate is fine | Same project helps |
| Is previewing whole app important? | Less important | Important |
| Is one rollback boundary useful? | No | Yes |
| Is traffic mostly idle/event-driven? | Yes | Less important |
A function architecture should not become a directory of tiny services only because the platform makes Functions easy to create.
Likewise, a full app service should not become the default place for every callback just because the main application already exists.
Long-lived connections and process behavior favor an app service
Function endpoints are designed around bounded invocations. That can be a mismatch when the application depends on a persistent process lifecycle.
App-service signals include:
- long-lived connections;
- background threads or continuously running consumers;
- stable in-process caches that materially improve the application;
- multiple routes sharing a persistent connection pool;
- process-level schedulers;
- framework plugins expecting a conventional server lifecycle;
- several coordinated HTTP and worker processes.
Raff Functions supports long execution windows—up to 1 hour by default and up to 24 hours on request—so duration alone does not force an endpoint into an App Platform. The more important distinction is whether the workload is still a bounded invocation or whether the application process itself needs to stay alive.
For example, a long report-generation request can still be poor HTTP architecture even if the Function can technically run for an hour. The better pattern may be to acknowledge the request, create asynchronous work, and let the client poll or receive a callback.
Do not choose a persistent app service merely to escape a short Function timeout. Choose it because the application lifecycle requires a persistent service.
Deployment workflow can decide the model before traffic does
Runtime behavior is not the only concern. The team's release workflow also matters.
A set of independent Functions can be attractive when each endpoint has a clear owner and release path. But a product team may prefer a full App Platform when the whole application should move through one Git-based deployment workflow.
Raff Apps currently provides:
- GitHub push-to-deploy;
- CLI deployment;
- buildpacks or Dockerfile builds;
- full Docker Compose import;
- immutable revisions;
- one-click rollback;
- pull-request preview environments;
- shareable preview URLs;
- web, private, worker, cron, and one-off service types.
Those features matter when an API is part of a broader application rather than an isolated endpoint.
A preview environment, for example, is much more valuable when reviewers need to test the frontend, API, database bindings, and related services together. If the workload is one webhook receiver, that whole application workflow may be unnecessary overhead.
Choose the deployment boundary that matches how the team changes the software, not only how the runtime executes it.
Cost should be compared at the service boundary
Functions and App Platform services use different economic models, so comparing one request with one app instance is misleading.
Raff Functions currently bills memory and active CPU, with requests and egress free and a monthly free tier after the required account activation. The product is designed for execution that follows demand.
Raff Apps currently uses flat per-instance tiers billed per second. Public application egress is $0, seats are not billed, and a spend cap is on by default. Current published tiers start at $3/month for the Micro tier, with higher ceilings as CPU, memory, and disk increase.
The useful cost question is:
Does this HTTP workload benefit more from usage that follows individual execution, or from an application service whose routes and processes share one runtime boundary?
Function endpoints can be economically attractive for sporadic or independently scaling traffic. An App Platform can be attractive when many related routes and processes use the same service continuously or benefit from one release boundary.
Do not use price alone to justify unnecessary fragmentation. Ten cheap Functions can still be harder to operate than one app service if they always change together.
The Serverless Function Pricing guide owns detailed Function metering. The Cloud VM vs App Platform guide owns the broader app-platform cost model.
Security controls exist in both models
A direct Function endpoint and an App Platform API both need application-layer security.
Both may need:
- authentication;
- authorization;
- CORS policy for browser clients;
- rate limiting or abuse controls;
- input validation;
- scoped secrets;
- safe logs;
- tenant isolation.
The Serverless API Security guide owns those controls for HTTP Functions.
Moving an endpoint into a persistent app service does not eliminate them. It may centralize middleware and policy across many routes, which can be an operational reason to choose the App Platform model when the API surface becomes tightly coupled.
Conversely, isolating a sensitive webhook or public callback in a separate Function can reduce its blast radius and keep third-party traffic away from the main application service.
The security question is therefore also about boundaries: should this endpoint share the main application's security middleware and release lifecycle, or should it be isolated as its own HTTP Function?
Raff makes a mixed HTTP architecture practical
A production application does not need to choose one runtime for every HTTP endpoint.
A practical Raff architecture can look like:
Frontend / clients ↓ Raff Apps web + API service ↓ Managed Database External providers ↓ Raff Functions webhooks/callbacks ↓ Managed Database / Object Storage
The main application receives customer traffic through an App Platform web service. External event receivers and occasional callbacks run as Functions. Both can connect to durable data services rather than forcing every workload into one process model.
This mixed model is useful because it keeps each boundary understandable:
- main application routes deploy together;
- webhooks scale independently;
- cron work can live in Functions or an Apps cron service depending on ownership;
- workers can live with the App project when they share its release lifecycle;
- isolated event processing can remain a Function.
At Raff, we would not move a healthy Function endpoint into Apps only because traffic grew. We would move it when the endpoint becomes application-shaped: tightly coupled routes, shared middleware, coordinated releases, or persistent process behavior become more important than independent execution.
