Skip to content

Service types

Each entry under services: has a type. A single entity can contain several services (an API, a frontend, a worker, a cron) — each gets its own build, its own port, and its own route prefix.

Your code lives under services/<service-name>/.

An Express/HTTP Node.js service. Listen on process.env.PORT.

name: my-api
services:
api:
type: node
path: /
const PORT = process.env.PORT || 8080;
require('http')
.createServer((req, res) => res.end('ok'))
.listen(PORT);

For TypeScript, add lang: typescript — the build expects src/index.ts and a tsconfig.json, and compiles with tsc.

services:
api:
type: node
lang: typescript
path: /

A Next.js app. Set standalone output in next.config.mjs:

/** @type {import('next').NextConfig} */
export default { output: 'standalone' };
name: my-dashboard
services:
web:
type: nextjs
path: /

The platform builds with npm run build and runs the standalone server — no Dockerfile needed. Build-time public vars go under the service’s build.env.

A Python service. Dependencies go in services/<name>/requirements.txt, installed during build.

name: my-service
services:
worker:
type: python
path: /
import os
from http.server import HTTPServer, BaseHTTPRequestHandler
PORT = int(os.environ.get('PORT', 8080))
HTTPServer(('', PORT), BaseHTTPRequestHandler).serve_forever()

A static site served over HTTP. Place your index.html at the service root.

name: landing-page
services:
site:
type: static
path: /

For a static site with a build step (Vite, Astro, and similar), declare a build: block. The platform runs the command and serves the output directory:

services:
site:
type: static
path: /
node_version: "22"
build:
command: "npm run build"
output: "dist"
env:
VITE_API_URL: "https://my-api.your-grid.cloudgrid.io"

node_version accepts "18", "20", "22", or "24" (default "22"), and applies to the static build step.

A scheduled job. Requires a schedule and cannot have a path or port.

services:
cleanup:
type: cron
schedule: "0 3 * * *" # daily at 3am
timezone: UTC
run: job # default: runs src/job.js or src/main.py

For HTTP-triggered cron (no code in your repo), point run at a URL:

services:
ping:
type: cron
schedule: "*/5 * * * *"
run: "https://my-api.your-grid.cloudgrid.io/cron/ping"
name: my-platform
services:
api:
type: node
path: /api
web:
type: nextjs
path: /
cron:
type: cron
schedule: "0 */6 * * *"
run: job
needs:
database: true
cache: true

Use path: to route traffic; set path: false for internal-only services. Use depends_on: to order startup. During grid dev, each service receives sibling URLs as environment variables so they can call each other locally.