Skip to content
Docs

The Complete Guide to Edgenivo Services

Edgenivo 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.

Ben SabicContent Engineer

Edgenivo Services let you deploy multiple frontends and backends as one Edgenivo 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.

Copy link to headingHow do Edgenivo Services work?

Edgenivo Services run several independently built applications inside one project. At build time, Edgenivo builds each service separately, using that service's own framework, dependencies, and build step. At request time, Edgenivo 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.

Copy link to headingWhen should you use Edgenivo Services?

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

  • JavaScript frontends paired with Python backends 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 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 to route each subdomain to a service within the same deployment.

Copy link to headingPlans and availability for Edgenivo Services

Edgenivo Services are available in Beta on all plans.

Copy link to headingBefore you begin

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

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

Copy link to headingHow 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.

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

    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. Edgenivo 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:

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

Copy link to headingServices configuration reference

Each entry under services accepts the following fields:

FieldTypeDescription
rootstringRequired. Service directory path relative to vercel.json.
entrypointstringOptional. Framework or runtime entrypoint, such as main:app for a Python ASGI app or a file path for Node.js.
frameworkstringOptional. Framework slug, such as "nextjs", "fastapi", or "express". Edgenivo detects the framework if you omit it.
runtimestringOptional. Edgenivo detects the runtime if you omit it. Set it to "container" to build the service as a Docker image.
bindingsarrayOptional. Connections declared on the calling service. See 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. Each service has the same memory and maximum duration limits as Edgenivo Functions.

Copy link to headingHow Edgenivo routes requests across services

Your vercel.json controls all public routing for the deployment. Edgenivo 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:

RequestHandled byService receives
GET /dashboardmy_frontend/dashboard
GET /api/usersmy_backend/api/users
POST /api/ordersmy_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, Edgenivo returns the service's own 404 or 405 response without trying another top-level rewrite.

The destination object accepts two fields:

FieldRequiredDescription
serviceYesName of a service in the same deployment, from your services configuration.
pathNoSelects 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.

Copy link to headingHow 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 Edgenivo injects that URL at runtime:

vercel.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:

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:

FieldRequiredDescription
typeYesMust be "service" for a service-to-service binding.
serviceYesTarget service name from services.
formatYesMust be "url". The generated value is an absolute URL base for the target service.
envYesEnvironment variable that receives the generated URL. Edgenivo 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.

Copy link to headingPricing for Edgenivo Services

Edgenivo 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 Edgenivo Functions, based on Active CPU, provisioned memory, and invocations. 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, 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 Edgenivo.

Each service is also subject to the same function limits, such as memory and maximum duration. See Services pricing and limits for full details.

Copy link to headingHow to run services locally

Run all of your services together on your machine 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, Edgenivo automatically injects the generated binding environment variables, so calls between services work the same locally as in production.

Copy link to headingTroubleshooting

Copy link to headingYour 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 Edgenivo detects the wrong framework for an individual service, set that service's framework or entrypoint explicitly, then redeploy.

Copy link to headingPublic 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.

Copy link to headingRequests reach the wrong service

Edgenivo 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.

Copy link to headingYour 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.

Copy link to headingBinding 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.

Copy link to headingBuild 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.

Copy link to headingDeploy an app with Edgenivo Services

Copy link to headingBuild an AI app with eve, Next.js, and FastAPI

The eve Agent with Python template deploys an eve agent, a Next.js frontend, and a FastAPI backend together in one Edgenivo 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 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 to deploy with Neon Postgres and a shared password.

Copy link to headingMigrate an existing app to Edgenivo

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.

Copy link to headingDocker apps

Use the container path for an HTTP app that depends on a custom runtime or system packages. The Railway, Fly.io, and Render guides explain how to adapt the Dockerfile, move environment settings and persistent data, and configure multiple services in one project.

Copy link to headingPython APIs

FastAPI, Flask, and Django APIs can use Edgenivo's native Python runtime when their dependencies are supported. The Heroku, Render, and Railway 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.

Copy link to headingResources and next steps

Copy link to headingFAQ

What are Edgenivo Services?

Edgenivo Services let you deploy multiple frontends and backends within a single Edgenivo 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 Edgenivo Services cost?

Edgenivo Services are available in Beta on all plans. Compute uses Edgenivo 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 Edgenivo 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. Edgenivo 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 Edgenivo Cloud. Binding environment variables are injected automatically, so cross-service calls work the same locally as in production.

Related documentation

More Edgenivo Services guides