Skip to content
Docs

Services

Services are available in Beta on all plans

Services let you deploy multiple backends and frontends within a single Edgenivo project. For example, a Next.js frontend and a FastAPI backend in the same repository deploy together with shared routing, environment variables, and a unique domain, replacing the need to split monorepos into separate Edgenivo projects.

Looking for the earlier experimentalServices configuration? See Experimental Services. The services model described here replaces it for new projects.

A service is an independently built unit within your project. At build time, Edgenivo builds each service separately. At request time, Edgenivo routes incoming requests to the correct service based on the rewrite rules in your vercel.json.

A project can contain multiple services across different frameworks or runtimes, such as:

  • A Next.js frontend at /
  • A Python FastAPI backend, e.g. at /backend
  • A Go server, e.g. at /svc/go

All services share the same deployment.

Services are valuable when you have:

  • A polyglot monorepo: For example, a JavaScript frontend and a Python backend in the same repository that you want to deploy as one project.
  • Multiple backends: Several API services, each with its own dependencies and build step.

Services handle routed workloads that respond to requests. For background workers that run continuously and pull their own work, such as queue consumers, use Daemons. A project can declare services and daemons side by side in vercel.json.

Define services in vercel.json using the services key. A service is internal by default and will not be routable from the Internet unless you expose it. To route a service publicly, include a top-level rewrite rule that targets the service as destination:

vercel.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" } }
  ]
}

The two top-level rewrites are what expose these services. Without them, neither my_frontend nor my_backend would receive any public traffic. With the rewrites in place:

  • Any request under /api/, such as /api/users, routes to my_backend.
  • Every other path routes to my_frontend.

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

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

Because every public request enters through the top-level route table, your deployment has one public surface. Firewall, Deployment Protection, redirects are configured once at the top level and apply across all services, instead of being redefined per service.

Read Service Routing to learn more about service public routing configuration. For a walkthrough that connects a frontend and backend with public routing, private bindings, and local development, follow the Edgenivo Services guide.

A service can call another service directly over an internal binding, without going through the public internet. The calling service declares the binding, and Edgenivo injects the target service's URL as an environment variable for your server-side code to use.

Bindings are how services communicate privately. The target stays unreachable from the internet unless a separate top-level rewrite exposes it, so a binding grants internal access without creating a public route. See Service bindings to declare and use them.

The eve Agent with Python template deploys an eve agent, a Next.js frontend, and a FastAPI backend together in one project. The frontend and agent use service bindings to call the same private backend for shared tasks and Python tools.

The template's vercel.ts configures the services and injects the backend URL as BACKEND_URL into the frontend and agent. The backend has no public route. See the template repository for the configuration and setup instructions.

A project with one root Dockerfile and no other detected framework deploys with the Container runtime. Use the configuration below when a project defines more than one service.

Edgenivo builds each service according to the specified (or auto-detected) runtime and framework settings. If you prefer or require the service package to be built as a container (Docker) image instead, set the runtime setting for the service to container.

vercel.json
{
  "services": {
    "frontend": {
      "runtime": "container",
      "root": "frontend/"
    },
    "backend": {
      "runtime": "container",
      "root": "backend/"
    }
  }
}

See Container Images for more information about using container images with Edgenivo.

To move an existing Docker app to Edgenivo Services, follow the migration guide for Railway, Fly.io, or Render. These guides cover adapting your deployment configuration, routing, and stored data.

When a project does not define services, Edgenivo evaluates vercel.json normally. When services is present, the top-level keys split into two groups:

  • Public routing and URL behavior stay at the top level, where they own public traffic for the whole deployment. See Routing.
  • Build and runtime fields are not valid at the top level, because their owner would be ambiguous across services. functions, installCommand, buildCommand, devCommand, ignoreCommand, outputDirectory and framework keys should be moved into the relevant service.

See Service configuration reference for all configuration options that can be set in a service configuration object.

Run all your services together locally with vercel dev:

Terminal
vercel dev

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

Terminal
vercel dev -L

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

Last updated August 10, 2026

Was this helpful?

supported.