---
title: The Complete Guide to Vercel Services
description: Vercel Services let you deploy multiple frontends and backends in one project on a shared domain. Learn how to define services in vercel.json, route requests by path prefix, and connect services with generated environment variables.
url: "https://vercel.com/kb/guide/vercel-services"
published: 2026-06-30
last_updated: 2026-10-22
authors: Ben Sabic
related_resources:
  - title: "Running Docker on Vercel"
    url: "https://vercel.com/kb/guide/docker"
    description: "Learn how to run Docker on Vercel by deploying OCI container images as Vercel Functions, storing them in Vercel Container Registry (VCR), and running containers in Vercel Sandbox."
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

Vercel Services let you deploy multiple frontends and backends as one Vercel project. Each service builds separately, while all services share a deployment and a public routing table. You can pair a Next.js frontend with a Python backend, route requests by path or hostname, and connect the services privately with bindings.

## How do Vercel Services work?

Vercel Services run several independently built applications inside one project. At build time, Vercel builds each service separately, using that service's own framework, dependencies, and build step. At request time, Vercel routes each incoming request to a service based on the rewrite rules in your `vercel.json`.

One project can combine frameworks and runtimes:

- A Next.js frontend at `/`
  
- A Python FastAPI backend, for example at `/api`
  
- A Go server, for example at `/svc/go`
  

Each service is internal by default and receives public traffic only when a top-level rewrite routes requests to it. All services share the same deployment, so they sit behind one public surface where Firewall, Deployment Protection, and redirects are configured once and apply across every service.

## When should you use Vercel Services?

Use Vercel Services when applications in one repository should deploy together as one project. Common cases include:

- JavaScript frontends paired with [Python backends](https://vercel.com/docs/functions/runtimes/python) that have their own dependencies and build steps.
  
- Multiple API services with different runtime or framework requirements.
  

For an app that one framework already handles, such as Next.js with API routes, deploy the project as usual. Choose [separate projects in a monorepo](https://vercel.com/docs/monorepos) when applications need independent deployments or rollbacks.

Separate hostnames don't require separate projects. Services can share a domain with path-based rewrites or use [hostname conditions](https://vercel.com/docs/services/routing#route-by-host) to route each subdomain to a service within the same deployment.

## Plans and availability for Vercel Services

Vercel Services are available in [Beta](https://vercel.com/docs/release-phases#beta) on [all plans](https://vercel.com/docs/plans).

## Before you begin

Prepare the application code you want to deploy as one Vercel project. The examples pair a frontend and a backend, but the `services` configuration also supports a single service.

Install the Vercel CLI with `npm i -g vercel` to run the local development commands.

## How to define and expose services in your project

Define your services in `vercel.json`, then expose them with top-level rewrites. Services are internal by default, so a service receives public traffic only when a rewrite routes requests to it.

1. Add a `services` block to `vercel.json`. Define each service with a `root` directory, and an `entrypoint` for backends that need one. Add top-level `rewrites` to route public traffic to each service.
   
   ```json
   {
     "services": {
       "my_frontend": {
         "root": "frontend/"
       },
       "my_backend": {
         "root": "backend/",
         "entrypoint": "main:app"
       }
     },
     "rewrites": [
       { "source": "/api/(.*)", "destination": { "service": "my_backend" } },
       { "source": "/(.*)", "destination": { "service": "my_frontend" } }
     ]
   }
   ```
   
   With these rewrites in place, any request under `/api/` routes to `my_backend`, and every other path routes to `my_frontend`. Without the rewrites, neither service would receive public traffic.
   
2. Deploy your project as you normally would. Vercel builds each service separately and serves them all from one deployment URL.
   

For the smallest possible setup, define a single service with a catch-all rewrite:

```json
{
  "services": { "api": { "root": "api/" } },
  "rewrites": [{ "source": "/(.*)", "destination": { "service": "api" } }]
}
```

## Services configuration reference

Each entry under `services` accepts the following fields:

| Field        | Type     | Description                                                                                                                                                                                      |
| ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `root`       | `string` | Required. Service directory path relative to `vercel.json`.                                                                                                                                      |
| `entrypoint` | `string` | Optional. Framework or runtime entrypoint, such as `main:app` for a Python ASGI app or a file path for Node.js.                                                                                  |
| `framework`  | `string` | Optional. Framework slug, such as `"nextjs"`, `"fastapi"`, or `"express"`. Vercel detects the framework if you omit it.                                                                          |
| `runtime`    | `string` | Optional. Vercel detects the runtime if you omit it. Set it to `"container"` to build the service as a Docker image.                                                                             |
| `bindings`   | `array`  | Optional. Connections declared on the calling service. See [How services call each other with bindings](https://vercel.com/kb/guide/vercel-services#how-services-call-each-other-with-bindings). |

When `vercel.json` includes a `services` key, public routing and URL behavior stay at the top level. These settings include `rewrites`, `redirects`, and `headers` and control public traffic for the whole deployment.

Put build and runtime fields inside the service that owns the build. Fields such as `functions`, `buildCommand`, `installCommand`, `devCommand`, `ignoreCommand`, `outputDirectory`, and `framework` aren't valid at the top level when `services` is present.

For all supported options, see the [service configuration reference](https://vercel.com/docs/services/config-reference). Each service has the same memory and maximum duration limits as Vercel Functions.

## How Vercel routes requests across services

Your `vercel.json` controls all public routing for the deployment. Vercel evaluates your top-level rewrites in order and routes each request to the first matching service, so the most specific rewrites should come before a catch-all rule. Each service receives public traffic only when a top-level rewrite targets it, with the `destination` set to an object such as `{ "service": "my_backend" }`.

With `/api/(.*)` routing to `my_backend` and everything else routing to `my_frontend`, requests route like this:

| Request            | Handled by    | Service receives |
| ------------------ | ------------- | ---------------- |
| `GET /dashboard`   | `my_frontend` | `/dashboard`     |
| `GET /api/users`   | `my_backend`  | `/api/users`     |
| `POST /api/orders` | `my_backend`  | `/api/orders`    |

The service receives the original request path. `GET /api/users` reaches `my_backend` as `/api/users`, so define your backend routes with the `/api/` prefix.

Once a request enters a service, that service handles the remaining routing. If no route matches, Vercel returns the service's own 404 or 405 response without trying another top-level rewrite.

The `destination` object accepts two fields:

| Field     | Required | Description                                                                                            |
| --------- | -------- | ------------------------------------------------------------------------------------------------------ |
| `service` | Yes      | Name of a service in the same deployment, from your `services` configuration.                          |
| `path`    | No       | Selects which route runs inside the service. It changes the route lookup, not the path your code sees. |

Each service can also define its own `headers`, `redirects`, `rewrites`, and `routes`, which run only after a top-level rewrite routes a request into it. To change the path your code observes, add a `request.path` transform to that service's `routes`.

## How services call each other with bindings

Service bindings let server-side code call another service over the internal network without exposing the target to public traffic.

Bindings are unavailable to callers that use the Go or Rust runtime. If a Go or Rust service needs to declare bindings, build it as a container image by setting `runtime` to `"container"`. Node.js and Python callers can use bindings directly.

You declare a binding on the calling service. The caller names the target service and the environment variable that should receive the generated URL, and Vercel injects that URL at runtime:

```json
{
  "services": {
    "orders": {
      "root": "services/orders/",
      "framework": "express",
      "bindings": [
        {
          "type": "service",
          "service": "inventory",
          "format": "url",
          "env": "INVENTORY_URL"
        }
      ]
    },
    "inventory": {
      "root": "services/inventory/",
      "framework": "fastapi",
      "entrypoint": "main:app"
    }
  },
  "rewrites": [{ "source": "/api/(.*)", "destination": { "service": "orders" } }]
}
```

Server-side code in `orders` reads the injected variable to build request URLs:

```typescript
await fetch(new URL('items/123', process.env.INVENTORY_URL));
```

The binding lets `orders` call `inventory` even though `inventory` has no public rewrite and stays unreachable from the internet. The binding fields are:

| Field     | Required | Description                                                                                                    |
| --------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| `type`    | Yes      | Must be `"service"` for a service-to-service binding.                                                          |
| `service` | Yes      | Target service name from `services`.                                                                           |
| `format`  | Yes      | Must be `"url"`. The generated value is an absolute URL base for the target service.                           |
| `env`     | Yes      | Environment variable that receives the generated URL. Vercel injects this value, so you don't set it yourself. |

The injected URL connects a preview deployment's `orders` service to the same preview's `inventory` service without a fixed hostname.

Internal calls skip the public request pipeline, including Firewall, Deployment Protection, top-level middleware, and CDN request accounting. Bindings grant internal access without authenticating or authorizing the call, so handle application-level authorization in your service code.

Bindings resolve only in a service's functions at runtime. They aren't available during builds or in middleware.

## Pricing for Vercel Services

Vercel bills Services based on the compute resources each service runs on, the requests services make to each other, and the data services return.

- Compute: Each service is billed the same as [Vercel Functions](https://vercel.com/docs/functions/usage-and-pricing), based on Active CPU, provisioned memory, and invocations. [Fluid compute](https://vercel.com/docs/fluid-compute) applies, so concurrent requests can share an instance.
  
- Service requests: When one service calls another over a binding, each call counts as one service request. Requests that arrive from the public internet aren't service requests. Service requests are [regionally priced](https://vercel.com/docs/pricing/regional-pricing), billed separately from CDN requests, and don't incur a separate CDN Request or Fast Data Transfer charge.
  
- Data transfer: The bytes a service returns are billed as Fast Origin Transfer, the same as other origin traffic on Vercel.
  

Each service is also subject to the same [function limits](https://vercel.com/docs/functions/limitations), such as memory and maximum duration. See [Services pricing and limits](https://vercel.com/docs/services/pricing) for full details.

## How to run services locally

Run all of your services together on your machine with `vercel dev`:

```bash
vercel dev
```

To run everything locally without authenticating with the Vercel Cloud, add the `-L` flag (short for `--local`):

```bash
vercel dev -L
```

In both cases, Vercel automatically injects the generated binding environment variables, so calls between services work the same locally as in production.

## Troubleshooting

### Your deployment doesn't build as services

Define services in a top-level `services` object in `vercel.json`, with a valid `root` for each service. If Vercel detects the wrong framework for an individual service, set that service's `framework` or `entrypoint` explicitly, then redeploy.

### Public requests cannot reach a service

Services receive public traffic only through a top-level rewrite. If the service should be public, add a rewrite whose `destination` targets it, for example `{ "source": "/api/(.*)", "destination": { "service": "my_backend" } }`. For a private service, check the caller's binding instead.

### Requests reach the wrong service

Vercel evaluates top-level rewrites in order and routes each request to the first match. If requests land on the wrong service, put your most specific rewrites before broader ones, and keep the catch-all `/(.*)` rule last.

### Your service receives an unexpected path

Services receive the original request path, including the matched prefix. `GET /api/users` reaches the service as `/api/users`, so mount your routes accordingly.

Use `path` in the rewrite's destination object to select a different route inside the service. To change the path your service code observes, add a `request.path` transform to the service's own `routes`.

### Binding calls fail or their URLs are missing

Declare the binding on the calling service and read the environment variable named by its `env` field. Make the call from a function at runtime; binding URLs don't resolve during builds or in middleware.

If the caller uses Go or Rust, build that service as a container image to use bindings. Bindings aren't available to callers using the Go or Rust runtime directly.

### Build or runtime configuration is ignored

When `services` is present, top-level build and runtime keys such as `functions`, `buildCommand`, `installCommand`, `devCommand`, `ignoreCommand`, `outputDirectory`, and `framework` aren't valid. Move them into the relevant service so the configuration has a single owner.

## Deploy an app with Vercel Services

### Build an AI app with eve, Next.js, and FastAPI

The [eve Agent with Python template](https://vercel.com/templates/eve/eve-agent-with-python) deploys an eve agent, a Next.js frontend, and a FastAPI backend together in one Vercel project. It includes a task manager that people can use through chat or a dedicated Tasks page.

Service bindings connect the Next.js server and eve agent to FastAPI without exposing a public backend route. Both use the same task endpoints, so a task created through chat is also available on the Tasks page. The [service configuration](https://github.com/vercel-labs/eve-agent-python-template/blob/main/vercel.ts) supplies the backend's address through `BACKEND_URL`.

The agent also calls Python endpoints to compute statistics and analyze text. Extend these endpoints with your own logic, or follow the [setup instructions](https://github.com/vercel-labs/eve-agent-python-template#getting-started) to deploy with Neon Postgres and a shared password.

## Migrate an existing app to Vercel

Choose a migration path based on how your app runs today and which dependencies it needs. The guides below cover platform-specific configuration, stored data, and the steps for switching production traffic.

### Docker apps

Use the container path for an HTTP app that depends on a custom runtime or system packages. The [Railway](https://vercel.com/kb/guide/migrate-railway-to-vercel), [Fly.io](https://vercel.com/kb/guide/migrate-fly-io-to-vercel), and [Render](https://vercel.com/kb/guide/migrate-render-to-vercel) guides explain how to adapt the Dockerfile, move environment settings and persistent data, and configure multiple services in one project.

### Python APIs

FastAPI, Flask, and Django APIs can use Vercel's native Python runtime when their dependencies are supported. The [Heroku](https://vercel.com/kb/guide/migrate-a-python-api-from-heroku-to-vercel), [Render](https://vercel.com/kb/guide/migrate-a-python-api-from-render-to-vercel), and [Railway](https://vercel.com/kb/guide/migrate-a-python-api-from-railway-to-vercel) guides cover Python entrypoints, databases, background work, and production cutover.

These guides also apply to standalone APIs. Use Services when the API and other application components should share a deployment.

## Resources and next steps

- Read [Services routing](https://vercel.com/docs/services/routing) for the full details on public routing and controlling the path your code sees.
  
- Learn how one service calls another with [service bindings](https://vercel.com/docs/services/bindings).
  
- Review [Services pricing and limits](https://vercel.com/docs/services/pricing) for how billing works across services.
  
- Compare services with separate [projects in a monorepo](https://vercel.com/docs/monorepos) to choose the right structure for your repository.
  
- Browse more [backend guides](https://vercel.com/kb/backend) for building and hosting APIs alongside your frontend.
  

## FAQ

### What are Vercel Services?

Vercel Services let you deploy multiple frontends and backends within a single Vercel project. Each service is an independently built unit that shares one deployment and one public surface. You expose a service to public traffic with a top-level rewrite, and services call each other privately with bindings.

### How much do Vercel Services cost?

Vercel Services are available in Beta on all plans. Compute uses Vercel Functions billing for Active CPU, provisioned memory, and invocations, with Fluid compute allowing concurrent requests to share an instance. Calls over bindings are billed as service requests, and responses incur Fast Origin Transfer charges.

### Which frameworks and runtimes do Vercel Services support?

One project can combine JavaScript frontends with Python or Go backends. Set each service's `framework` to a slug such as `"nextjs"`, `"fastapi"`, or `"express"`, or omit it for automatic detection.

Set `runtime` to `"container"` to build a service as a Docker image. This is also the supported option when a Go or Rust caller needs service bindings, which aren't available with those runtimes directly.

### When should I use services instead of separate projects?

Use Services when applications in one repository should share a deployment, such as a frontend paired with a backend or several APIs that ship together. Choose separate projects when applications need their own deployment and rollback schedules. Services can route traffic by hostname as well as path, so separate subdomains alone don't require separate projects.

### How do services communicate with each other?

Public requests reach a service through top-level rewrites in your `vercel.json`. For private calls between services, declare a binding on the calling service. Vercel injects the target service's URL into an environment variable that your server-side code reads, and the call stays on the internal network without a public route.

### How do I run services locally?

Run `vercel dev` to start all of your services together on your machine, or `vercel dev -L` (the `-L` flag is short for `--local`) to run them without authenticating with the Vercel Cloud. Binding environment variables are injected automatically, so cross-service calls work the same locally as in production.

## Related Resources

- [Running Docker on Vercel](https://vercel.com/kb/guide/docker): Learn how to run Docker on Vercel by deploying OCI container images as Vercel Functions, storing them in Vercel Container Registry (VCR), and running containers in Vercel Sandbox.

## More Vercel Services guides

- [How to migrate from Google Cloud Run to Vercel](/kb/guide/migrate-cloud-run-to-vercel): Move a Cloud Run service or worker to Vercel. Compare runtimes, preserve Google Cloud access, and plan jobs, validation, and production cutover.
- [How to use Vercel Container Registry](/kb/guide/how-to-use-vercel-container-registry): Push, store, and pull OCI container images with Vercel Container Registry, then deploy them to Vercel Functions and Vercel Sandbox.
- [How to migrate from Fly.io to Vercel](/kb/guide/migrate-fly-io-to-vercel): Move an app from Fly.io to Vercel. Map configuration, choose Functions or Daemons, plan persistent storage, and verify the production cutover.