Buildpack plugins

Plugins add framework support on the server. They do not run inside your repo.

Relay buildpack plugins are JSON definitions stored on the agent. They participate in framework detection before the built-in buildpacks, then render a Dockerfile template when they match. Operators can install them from local files, pasted JSON, catalog search, or verified HTTPS URLs.

Example install
relay plugin search astro
relay plugin install ./plugins/astro-static.json \
  --url http://127.0.0.1:8080 \
  --token YOUR_TOKEN
relay plugin install-url https://example.com/plugins/astro-static.json \
  --sha256 <hex>

relay plugin list --url http://127.0.0.1:8080 --token YOUR_TOKEN
Plugin model

A plugin is a detection rule set plus a Docker plan template.

This is deliberately smaller than a generic code plugin system. The agent needs enough information to decide whether the plugin matches a repo and how to build and run that repo if it does.

Detection happens on the agent

Relay inspects the uploaded repo snapshot on the server. Plugins are applied there, so every deploy for that agent sees the same framework support.

Priority decides matching order

Plugins are prepended ahead of built-ins. Higher priority wins, so a plugin can override the default behavior for a specific framework shape.

The output is still a build plan

A plugin does not bypass the rest of Relay. It still resolves to a build image, run image, service port, and rendered Dockerfile.

Install trust is explicit

Remote plugin installs are owner-only, require HTTPS, and can be pinned with SHA256 so the server verifies the exact JSON before it writes anything under data/plugins/buildpacks.

Installing plugins

The CLI and admin UI can both mutate the plugin set when the server allows it.

A plugin install is an authenticated API write to the agent. In production, leave plugin mutation off unless you are actively curating framework support.

1

Turn on mutation intentionally

Set `RELAY_ENABLE_PLUGIN_MUTATIONS=true` only while administering plugins.

2

Choose a source

Install from a JSON file, paste JSON in the owner dashboard, use catalog search, or use `relay plugin install-url <https-url> --sha256 <hex>` for a verified remote source.

3

List what is active

Use `relay plugin list`, the owner dashboard Plugins tab, or `GET /api/plugins/buildpacks` to inspect the live set.

4

Turn mutation back off

Once the plugin is installed, the agent still loads it even after you disable further mutations.

Plugin API
GET    /api/plugins/buildpacks
POST   /api/plugins/buildpacks
POST   /api/plugins/buildpacks/install-url
DELETE /api/plugins/buildpacks/:name
Authoring plugins

Write the plugin around file signals and a concrete build/run plan.

A good plugin is narrow. Match on a specific framework shape, render a Dockerfile that is easy to reason about, and avoid shadowing unrelated repos with broad rules.

name

Unique plugin id used for storage and listing.

priority

Higher numbers match before lower ones.

detect

Files, directories, extensions, or package.json signals that identify the framework.

plan

Kind, images, service port, commands, and the Dockerfile template.

Plugin shape
{
  "name": "astro-static",
  "priority": 900,
  "detect": {
    "files_any": ["astro.config.mjs", "astro.config.ts"],
    "package_deps_any": ["astro"]
  },
  "plan": {
    "kind": "astro-static",
    "service_port": 80,
    "dockerfile_template": "FROM node:22 AS builder\n...\nFROM nginx:alpine\n..."
  }
}
Built-in buildpacks

Built-ins cover the common stacks before custom plugins fill the gaps.

Built-ins cover the most common stacks. Plugins run first and can override detection for any of them. If detection lands on a built-in, the agent renders its Dockerfile and runs the build with no additional config.

node-next

Next.js apps detect next in package.json and build with next build.

node-vite

Vite-based SPAs match vite in package.json and output a static dist/.

expo-web

Expo web targets detect expo in package.json and run web builds.

sprint-ui

Sprint UI apps detect Sprint UI signals and render the expected web build plan.

bun

Bun apps detect bun.lock or Bun package usage and build with Bun-aware commands.

node-generic

Any Node.js project with a start script and no framework-specific signal.

go

Go modules detect go.mod, cross-compile, and run the resulting binary.

dotnet

ASP.NET Core apps detect .csproj and build with dotnet publish.

python

Python apps, including Flask and FastAPI, detect pyproject.toml or requirements.txt.

ruby

Rails and Rack apps detect Gemfile and run the Ruby build and boot path.

java

Maven or Gradle projects detect pom.xml or build.gradle and package a JAR.

rust

Rust binaries detect Cargo.toml and build in release mode.

c-cpp

C and C++ projects detect a Makefile and compile with make.

wasm-static

WebAssembly targets compiled to static files detect wasm-pack or similar.

static

Pure static sites use any directory with an index.html and no build step.

dockerfile

An explicit repo-relative Dockerfile or an auto-detected nested Dockerfile under the selected app roots overrides all detection.

What comes next

CI step plugins, versioned packages, and stronger trust policy are still on the roadmap.

The current plugin model is deliberately narrow. Future types extend it without changing how existing buildpack plugins work.

CI step plugins

relay ci test and relay ci lint would run typed check steps against the uploaded snapshot before the build starts. Plugins supply the command, image, and pass/fail rule.

Versioned packages

The next missing layer is upgradeable plugin packages with version tracking, not basic discovery. Search already exists today, but there is still no plugin upgrade flow or signed release channel.

Signed catalogs and trust policy

HTTPS and optional SHA256 cover transport and integrity, but Relay still lacks catalog signatures, allowlists, and richer trust policy for remote plugin sources.

Cross-compile artifacts

relay build --target linux-amd64 would separate the build artifact from the image, enabling multi-arch deployments and pre-built binaries without re-running the full build for each target.