Service
A service is a long-running process, such as a database, that a task needs in order to do its work.
Services help tasks do their work — for example, a database for your application or an API for your integration tests.
Services can run in a container or be forwarded from a Kubernetes cluster. Each service a task needs is reachable on the container network by the service's name.
Local tasks can also use needs, but hammerkit does not provide DNS resolution for them. Instead, the connection details of each needed service are passed to the task as environment variables (see environment hints).
Container
Like container tasks, container services need an image to run. Tasks declare which services they need, and hammerkit ensures those services are running before the task executes.
Use healthchecks to ensure that a service is running and ready to be used.
services:
postgres:
image: postgres
envs:
POSTGRES_USER: api
POSTGRES_DB: api
POSTGRES_PASSWORD: 123456
healthcheck:
cmd: "pg_isready -U api"
ports:
- 5432
tasks:
api:
image: node:alpine
needs: [postgres]
cmds:
- node index.jsKubernetes
Kubernetes services let tasks use resources from local and remote Kubernetes clusters. This makes it easy to integrate with resources from development or staging environments, and to debug or troubleshoot your application with data from other environments.
services:
postgres-staging:
context: staging
ports:
- 5432:5432
selector:
type: deployment
name: postgres
tasks:
api-staging:
image: node:alpine
needs: [postgres-staging]
cmds:
- node index.jsConnecting from a container task
A container task shares a network with its needed services and reaches each one by
its service name as the hostname, on the service's container port. You
don't publish a port for this — ports are only needed to reach a service from
your host.
For the postgres service above (exposing 5432), a container task connects with
a URL like postgres://api@postgres:5432/api — postgres is the service name and
5432 the container port. Keep that string in a shared top-level envs block so
the service and the task agree on it:
envs:
DATABASE_URL: postgres://api@postgres:5432/api
services:
postgres:
image: postgres:16-alpine
envs:
POSTGRES_USER: api
POSTGRES_DB: api
POSTGRES_HOST_AUTH_METHOD: trust
healthcheck:
cmd: "pg_isready -U api"
ports:
- 5432
tasks:
migrate:
image: node:24-alpine
needs: [postgres]
envs:
DATABASE_URL: $DATABASE_URL
cmds:
- node migrate.jsEnvironment hints for local tasks
A local task (a task without an image) is not part of that container network, so
hammerkit instead injects the connection details as environment variables.
For every needed service the following variables are available, where NAME is the
uppercased service name:
HAMMERKIT_<NAME>_HOST- host the service is reachable on.HAMMERKIT_<NAME>_PORT- the primary published port.HAMMERKIT_<NAME>_PORT_<containerPort>- the published port for a specific container port. The suffix is always the numeric container port (ports cannot be named), so this is mainly useful for services that expose more than one port.
For a service named postgres exposing port 5432 a local task receives
HAMMERKIT_POSTGRES_HOST, HAMMERKIT_POSTGRES_PORT and HAMMERKIT_POSTGRES_PORT_5432.
Service dependencies
Like tasks, services can declare deps and needs. Use deps when a service
requires a task to run first (for example building an image input), and needs
when a service depends on another service.
services:
api:
image: node:alpine
deps: [install]
needs: [postgres]
cmd: node index.js
postgres:
image: postgres:16-alpine
ports: [5432]
tasks:
install:
image: node:alpine
cmds:
- npm ciStarting and stopping services
Services start and stop automatically based on the needs of the tasks you run. They can also be controlled directly with the CLI:
hammerkit upstarts the services.hammerkit downstops the services.
This is useful to keep shared services such as a database running across multiple task runs.
A service's container is recreated when it starts, so data written inside it is lost on the next start unless you attach a volume. Declare a volume to persist a database's data — or to seed/back it up with store / restore.