Skip to main content
A Project is the central workload resource in Caravanserai. It groups one or more containers — called services — that must run together on a single node. Services share a Docker bridge network and resolve each other by service name, exactly like Docker Compose.

Schema

Top-level fields

string
required
Must be caravanserai/v1.
string
required
Must be Project.
object
required
Identity metadata for the resource.
string
required
Unique name for the Project within the cluster. Used to reference the Project in caractrl commands and as the basis for Docker resource names (cara-{name} for the network, {name}-{service} for containers).
object
Arbitrary key/value pairs for grouping and selection.
object
required
The desired state of the Project.

spec.services

The ordered list of containers to run. At least one service is required.
ServiceDef[]
required
One or more service definitions.
string
required
Name of the service within the Project. This name is used as the DNS hostname inside the shared bridge network — other services can reach this container at http://{name}:{port}.
string
required
Docker image reference, for example nginx:alpine or postgres:15.
EnvVar[]
Environment variables injected into the container at runtime.
string
required
Environment variable name, for example DATABASE_URL.
string
Environment variable value.
VolumeMount[]
Volumes to attach to this container. Each entry must reference a volume defined in spec.volumes.
string
required
Name of the volume to mount. Must match a name in spec.volumes.
string
required
Absolute path inside the container where the volume is mounted, for example /var/lib/mysql.

spec.volumes

VolumeDef[]
Named volumes shared across services. Optional.
string
required
Volume name. Referenced by spec.services[].volumeMounts[].name.
string
default:"Ephemeral"
required
Volume lifecycle type. Currently the only supported value is Ephemeral: the volume is discarded when the Project is stopped or moved to another node. No backup or restore occurs.

spec.ingress

IngressDef[]
HTTP routing rules for exposing services. Optional.
string
required
Identifier for this ingress rule.
string
Hostname for the ingress rule. If the value contains a dot it is used verbatim; otherwise the final hostname is assembled as {host}.{environment}.{baseDomain}.
object
required
The backend service and port to forward traffic to.
string
required
Name of the service (must match a name in spec.services) to route traffic to.
integer
required
Port on the target service to forward traffic to.
object
Visibility settings for the ingress endpoint.
string
default:"Internal"
required
Controls where the route is reachable. Currently the only supported value is Internal, which limits access to the Headscale overlay network.

spec.expireAt

string
An RFC 3339 timestamp. When set, the garbage collection controller automatically deletes the Project after this time. Useful for ephemeral preview environments. Example: 2026-04-30T00:00:00Z.

Examples

A single-service Project running an nginx web server. No volumes or ingress required.
nginx-project.yaml

Validation

Caravanserai validates your manifest when you run caractrl apply. The following fields are required:
  • apiVersion
  • kind
  • metadata.name
  • spec.services (at least one entry)
  • spec.services[].name and spec.services[].image on each service
  • spec.volumes[].name and spec.volumes[].type on each volume
  • spec.ingress[].name, spec.ingress[].target.service, and spec.ingress[].target.port on each ingress rule
If you define a volumeMount in a service, the referenced volume name must exist in spec.volumes. The API rejects manifests with dangling volume references.
Service names resolve as hostnames within the Project’s Docker bridge network. Use the service name directly as the hostname when configuring inter-service connections — for example, WORDPRESS_DB_HOST: db connects the app service to the db service.