FerryDocs
Developers

Blueprint reference

The keys of a ferry.yaml or render.yaml blueprint, and the commands that apply it.

Edit on GitHub

A is one file that describes your , your and your . Ferry reads the render.yaml format of , with its keys, and adds a few keys of its own.

An creates what is not there and updates what changed. It never deletes.

An example

examples/blueprint/ferry.yaml
envVarGroups:
  - name: shared-settings
    envVars:
      - key: APP_ENV
        value: production

databases:
  - name: app-db
    postgresMajorVersion: "16"
    databaseName: app
    user: app
    plan: basic-256mb        # 256 MiB of memory

services:
  - type: redis
    name: cache
    plan: starter            # 256 MiB of memory

  - type: web
    name: hello
    runtime: image
    image:
      url: nginx:alpine
    port: 80
    healthCheckPath: /
    numInstances: 2
    plan: starter            # 512 MiB / 0.5 CPU per instance
    envVars:
      - fromGroup: shared-settings
      - key: DATABASE_URL
        fromDatabase:
          name: app-db
          property: connectionString
      - key: REDIS_URL
        fromService:
          type: redis
          name: cache
          property: connectionString
      - key: SESSION_SECRET
        generateValue: true

  - type: cron
    name: nightly
    runtime: image
    image:
      url: busybox:stable
    schedule: "0 3 * * *"
    startCommand: echo "nightly job ran at $(date)"
    memoryLimit: 64M         # per run
    cpuLimit: 250m

This file describes one env group, one database, one datastore, one with two instances and one . The web service gets the URLs of the two datastores and a random secret.

Apply a blueprint

Do a first. It shows the changes and writes nothing.

Terminal
ferry blueprint apply --dry-run   # show what would change
ferry blueprint apply             # apply ./ferry.yaml, else ./render.yaml
ferry blueprint apply infra/render.yaml

Without a file name, the CLI looks for ./ferry.yaml, then for ./render.yaml. To get the raw JSON result, run ferry --json blueprint apply. See ferry blueprint apply.

The first apply of the example creates each resource. Then it puts a deploy in the queue for each service that has a source:

ferry blueprint apply examples/blueprint/ferry.yaml
Applied blueprint examples/blueprint/ferry.yaml

Created:
  + env group shared-settings
  + datastore app-db
  + datastore cache
  + service hello
  + service nightly

Queued deploys:
  dep-3271cdfd1415400d9a5e  hello (blueprint, queued)
  dep-0fe672f0b3a4486991a9  nightly (blueprint, queued)

Follow a deploy with: ferry logs --deploy <id> -f

What an apply changes

  • Ferry checks the full file before it writes. If one entry is not valid, the apply stops with an error and the server does not change.
  • Ferry writes the env groups, then the datastores, then the services.
  • Ferry deletes nothing. A resource or a variable that you remove from the file stays on the server.
  • A second apply of the same file changes nothing. Ferry keeps each generated secret.
  • Ferry runs one apply at a time. An apply continues to its end when the client disconnects.
ChangeResult
A new service with a repo or an imageA deploy with the trigger blueprint
A new service with no repo and no imageNo deploy. Run ferry up NAME to deploy it.
type, the source, a build key, port, healthCheckPath or diskA blueprint deploy
Only the startCommand of a cron jobA restart
Only plan, memoryLimit or cpuLimitA restart of the live service, with no build
Only variables or links to env groupsA restart of the live service (trigger env_change)
numInstances, domains, schedule, autoDeployNo deploy. Ferry scales, changes the routes or saves the value.
The limits of a datastoreNew limits in place, with no restart

A service that is not in the file restarts too when it links to an env group that the apply changed. Ferry does not deploy or restart a suspended service. The apply gives a warning: resume the service to apply the changes.

A key that you remove goes back to its default

The file gives the full settings of a service. When you remove a key, the next apply puts back its default. Only four things stay: numInstances, domains, the limits and the source (repo with branch, or image).

Top-level keys

KeyContains
envVarGroupsEnv groups
databasesPostgres databases
servicesServices, and Redis datastores with type: redis or keyvalue
projectsThe projects of Render. Ferry applies the services, databases and envVarGroups of each entry of environments to the environment production of this server, with a warning.

Ferry ignores each other top-level key with a warning. This includes the x- keys that hold a . The anchor continues to work.

Ferry keeps each value as you wrote it: 3.10 stays 3.10 and 0123 stays 0123. A boolean is true, false, yes, no, on, off, 1 or 0. The same key two times in one block is an error.

Services

Each entry of services needs a type and a name. All other keys are optional.

typeAlso acceptedResult
webweb_serviceA web service. With runtime: static, a static site.
pservprivate_service, privateA
workerbackground_workerA
croncron_jobA cron job
staticstatic_siteA
redis, keyvaluekey_valueA Redis datastore, not a service

Keys of a service

KeyDefaultValue
namerequired1 to 40 lowercase letters, digits or -. It starts with a letter and does not end with -. It is also the hostname on the private network.
runtimesee belowdocker, image, node, python, go, rust, ruby, static or auto. Also nodejs, javascript, bun, python3, golang. The old key env also works.
repononeA git URL (https://, ssh://, git://, file://, git@host:path) or an absolute path on the server
branchmainThe to build and to follow
imagenoneAn : nginx:alpine or { url: nginx:alpine }. Set repo or image, not the two.
rootDirrepository rootThe , a relative path
dockerContextnoneThe root directory, when the entry has no rootDir
dockerfilePathDockerfileRelative to the root directory
buildCommandnoneThe build command of a native runtime
startCommandnoneThe command that starts the app. dockerCommand is the same key.
staticPublishPathnoneThe folder that a static site serves
portdetectedA : the port of the app, 1 to 65535
healthCheckPathTCP checkAn HTTP path. The answer must be below 400 before a deploy goes live.
numInstances11 to 50. Ferry ignores it on a cron job.
autoDeploytrueA deploy at each push to branch
autoDeployTriggernonecommit (on), off, or checksPass (on, with a warning). It wins over autoDeploy.
schedulenoneRequired for a cron job: a of 5 fields in UTC, or @hourly
disk.mountPathnoneThe of a : an absolute path, not /
domainsnoneA list of custom domains
plan, memoryLimit, cpuLimitnoneSee Plans and limits.
envVarsnoneSee Env vars and env groups.

The default runtime is image when the entry has an image, and static for a static site. For other entries, Ferry finds the runtime from your files. If the CLI runs on the server, repo can also be a path relative to the blueprint file, such as ./api. The CLI changes it into an absolute path.

Some keys work only on some types:

  • healthCheckPath: web services, private services and static sites.
  • schedule: cron jobs only.
  • disk: web services, private services and workers, with 1 instance. Ferry accepts disk.name and disk.sizeGB and does not use them.
  • domains: web services and static sites.

Datastores

Postgres

Each entry of databases creates one Postgres datastore with the image postgres:<version>-alpine.

KeyDefaultValue
namerequiredThe same rules as the name of a service. A service and a datastore cannot have the same name.
postgresMajorVersion16Digits and dots only
databaseNamename, with _ for -1 to 63 letters, digits or _. The first character is not a digit.
userdatabaseNameThe same rules as databaseName
plan, memoryLimit, cpuLimitnoneSee Plans and limits.

Redis

An entry of services with type: redis or type: keyvalue creates a Redis datastore. Render calls it a . Ferry reads only type, name, plan, memoryLimit and cpuLimit.

Ferry runs redis:7-alpine with a password, append-only persistence and a maxmemory of 3/4 of the memory limit.

A datastore that exists

After the first apply, an apply changes only the limits of a datastore. If postgresMajorVersion, databaseName or user is different, the apply continues with a warning:

database 'app-db': postgresMajorVersion '17' differs from the existing '16'; datastores are not changed in place (ignored)

Plans and limits

Each container gets a and a . A plan gives them. The memoryLimit and cpuLimit replace the values of the plan, one key at a time.

plan of a serviceMemoryCPU
free, starter512 MiB0.5
standard2 GiB1
pro4 GiB2
pro plus8 GiB4
pro max16 GiB4
pro ultra32 GiB8

The limits apply to each instance and to each run of a cron job. A static site has no plans: Ferry ignores its plan with no warning, but memoryLimit and cpuLimit apply.

The plan of a datastore sets the memory only:

plan of a datastorePostgresRedis
basic-<size>, pro-<size>, accelerated-<size>The size in the name, such as basic-256mb or pro-4gbUnknown plan
free, starter256 MiB256 MiB
standard1 GiB1 GiB
pro4 GiB5 GiB
pro plus8 GiB10 GiB

Ferry ignores the case and the separator of a plan name: pro plus, Pro_Plus and pro-plus are the same plan. An unknown plan sets nothing and gives a warning.

KeyValuesRange
memoryLimitA size: 512M, 1G, 1.5G, 2GiB. A plain number is : 768.16 MiB to 1 TiB
cpuLimitA number of CPUs: 0.5, 2. Or : 250m is 0.25 CPU.0.01 to 512

The value 0 gives the server default. A value that Ferry cannot read, or a value out of the range, stops the apply.

With no plan and no key, a new resource gets the server defaults: --default-memory-limit and --default-cpu-limit of ferryd. A resource that exists keeps its limits.

Env vars and env groups

envVars is a list. Each entry has one form only:

EntryResult
{ key, value }A literal value. A null value becomes an empty string.
{ key, generateValue: true }A of 64 hex characters. A new apply never changes it.
{ key, sync: false }Ferry sets nothing. Each apply gives a warning until you set the variable.
{ key, fromDatabase: { name, property } }A to a Postgres database: ${{datastore.NAME.PROPERTY}}
{ key, fromService: { type, name, property } }A reference to a service: ${{service.NAME.PROPERTY}}. With type: redis or keyvalue, a reference to a Redis datastore.
{ key, fromService: { type, name, envVarKey } }A copy of a variable of a different service. Ferry copies the value at each apply.
{ fromGroup: NAME }A link to the env group NAME. Services only.

An entry with two sources is an error. If a key is two times in the list, the last entry wins, with a warning. One value has 32 KiB at most. The variables of one service or group have 256 KiB at most together. Without a type, fromService looks for the name in the services and in the datastores.

Reference properties

propertyTargetValue
connectionString (or url, internalUrl)DatastoreThe URL on the private network, such as postgresql://app:…@app-db:5432/app
externalConnectionString (or externalUrl)DatastoreThe same URL through the port that the server publishes
host (or hostname)Datastore, serviceThe name on the private network: app-db
port, hostportDatastore, service with a port5432 and app-db:5432
user (or username), passwordDatastoreThe credentials
database (or databaseName)PostgresThe name of the database
internalUrlService with a porthttp://NAME:PORT
url (or externalUrl)Web service, static siteThe public URL

Web services, private services and static sites have a port.

envVarGroups

Each entry of envVarGroups creates one env group. A service links to it with fromGroup.

KeyDefaultValue
namerequired1 to 64 letters, digits, -, _ or .
envVarsnoneThe same entries as a service, but not fromGroup

The own variables of a service win over the variables of its groups. A group with a later link wins over a group with an earlier link.

Differences from render.yaml

Most render.yaml files apply with no change. A key that Ferry does not support is never an error: Ferry ignores it with a warning, such as service 'api': ignoring unsupported key 'region'.

Key or featureOn Ferry
region, scaling, previews, preDeployCommandIgnored, with a warning
ipAllowList, diskSizeGB, maxmemoryPolicy on a datastoreIgnored, with a warning
previewValue and other Render keys of envVarsIgnored, with a warning
image.credsIgnored, with a warning. Docker must pull the image with no credentials.
Projects and environmentsFerry has no projects. A blueprint applies to the environment production only. Services and datastores of another environment with the same names do not change.
An entry with no repoRender uses the repository of the blueprint. Ferry has no default: set repo, or run ferry up NAME.
autoDeployTrigger: checksPassA deploy at each commit, with a warning. Ferry does not wait for checks.
A runtime that Ferry cannot build, such as elixirA warning. Ferry finds the runtime from your files: add a Dockerfile.
The plan free0.5 CPU, not 0.1
Not supported. Use environment variables.
portA Ferry key. Render has no such key.

On this page