Skip to main content
Services are the frontend and backend applications that make up your project. Your coding agent defines them as service blocks in specific.hcl, each with a build step, a start command, and environment variables connecting it to other services and resources.

Public and internal endpoints

Services with a public endpoint are accessible over the internet via HTTPS. The URL is assigned automatically during deployment and shown in the terminal output.
service "web" {
  build = build.web
  command = "npm start"

  endpoint {
    public = true
  }

  env = {
    PORT = port
  }
}
Services without a public endpoint — or without any endpoint at all — are only reachable by other services within the same project. This is the default for backend APIs that should not be directly exposed.

Inter-service communication

Services can reference each other to communicate over a private network. This is useful for backend-to-backend calls where traffic should stay internal.
service "api" {
  build = build.api
  command = "./api"

  endpoint {}

  env = {
    PORT = port
  }
}

service "worker" {
  build = build.worker
  command = "./worker"

  env = {
    API_URL = service.api.private_url
  }
}
Available reference attributes:
  • service.<name>.private_url — Internal URL (host and port), only reachable by other services
  • service.<name>.public_url — Public URL, only available for services with public = true
  • service.<name>.host — Internal hostname
  • service.<name>.port — Internal port
For frontend services that run in the browser, use public_url instead of private_url since the browser cannot reach internal addresses:
service "web" {
  build = build.web
  command = "npm start"

  endpoint {
    public = true
  }

  env = {
    PORT = port
    API_URL = service.api.public_url
  }
}

service "api" {
  build = build.api
  command = "./api"

  endpoint {
    public = true
  }

  env = {
    PORT = port
  }
}

Workers

Services without any endpoint act as background workers. They are deployed the same way as other services but don’t receive HTTP traffic. Workers are common for queue consumers, scheduled jobs, or other background processing.
service "worker" {
  build = build.worker
  command = "npm run worker"

  env = {
    DATABASE_URL = postgres.main.url
  }
}

Multiple endpoints

A single service can expose multiple named endpoints on different ports. Each endpoint can be independently public or internal.
service "api" {
  build = build.api
  command = "./api"

  endpoint "main" {
    public = true
  }

  endpoint "admin" {}

  env = {
    MAIN_PORT = endpoint.main.port
    ADMIN_PORT = endpoint.admin.port
  }
}
Other services reference named endpoints with service.<name>.endpoint.<endpoint>.private_url.

Environment variables

All connection details — database URLs, storage credentials, secrets — are automatically injected as environment variables. Your coding agent wires these up in the env block, and the same references resolve to the correct values in both local development and production.
service "api" {
  build = build.api
  command = "./api"

  endpoint {
    public = true
  }

  env = {
    PORT         = port
    DATABASE_URL = postgres.main.url
    REDIS_URL    = redis.main.url
    S3_ENDPOINT  = storage.uploads.endpoint
  }
}