Ir al contenido

Buscar en la documentación

Busca en la documentación de Skiffly

Configuración como código

Describe un proyecto en `.skiffly/skiffly.ts` con `@skiffly/config`, previsualiza el diff con `skiffly config plan` y concílialo con `skiffly config apply`.

El archivo replica el SDK railway/iac de Railway: los builders conservan sus nombres y defineRailway pasa a ser defineSkiffly. La CLI compara el archivo con un entorno y aplica la diferencia a través de la API pública. No hay archivo de estado; Skiffly es la fuente de verdad, así que ejecutar apply dos veces no hace nada.

Preparación#

npm i -g skiffly && skiffly login
pnpm add -D @skiffly/config        # opcional: tipos en tu editor (la CLI incluye su propia copia)
.skiffly/skiffly.ts
import { defineSkiffly, github, postgres, project, service } from "@skiffly/config";
 
export default defineSkiffly(() => {
  const db = postgres("db");
 
  const web = service("web", {
    source: github("acme/web"),
    build: "pnpm build",
    start: "pnpm start",
    healthcheck: "/health",
    env: {
      NODE_ENV: "production",
      DATABASE_URL: db.env.DATABASE_URL,
    },
    domain: true,
  });
 
  return project("my-app", { resources: [db, web] });
});

skiffly.config.ts en la raíz del proyecto, .js, .mjs y .json también funcionan. TypeScript se transpila en memoria; sin paso de build.

Comandos#

skiffly config init                 # adopta un proyecto existente: escribe el archivo a partir del entorno vinculado
skiffly config validate             # evalúa el archivo, sin llamadas a la API
skiffly config plan [--prune]       # + service db, ~ env web.DATABASE_URL, - volume /data
skiffly config apply [--yes] [--prune] [--no-deploy]
skiffly config plan
my-app / production
 
  + service db  # will deploy
      + source.image = "postgres:17"
      + port = 5432
      + env.POSTGRES_PASSWORD = <generated password>
      + volume /var/lib/postgresql/data = "10 GB"
  ~ service web  # will deploy
      ~ env.DATABASE_URL: "postgres://…" → "${{db.DATABASE_URL}}"
      + domain (generated)
  • plan y apply aceptan -p/--project, -e/--environment, -f/--file, --json, --show-secrets.
  • Lo que el archivo omite no se gestiona. Un servicio sin env conserva sus variables intactas; env: {} significa "sin variables" y, con --prune, las elimina.
  • Los recursos en Skiffly que el archivo no declara se conservan a menos que uses --prune; apply pregunta antes de eliminar (--yes en CI).
  • Los servicios modificados se despliegan al final de apply; --no-deploy lo omite.

Servicios#

OpciónEjemploCorresponde a
sourcegithub("acme/web", { branch: "main", rootDir: "apps/web" }), image("nginx:1.27"), empty()origen
build"pnpm build" o { builder: "DOCKERFILE", dockerfilePath: "Dockerfile.prod" }configuración del build
start"node server.js" (null lo borra)comando de inicio
healthcheck"/health" o { path, timeout }health check
env{ KEY: "v", URL: db.env.DATABASE_URL, SECRET: preserve(), TOKEN: generate("hex32") }variables del servicio
port8080puerto
domaintruedebe existir un dominio generado
domains["app.example.com"]dominios propios
volumes["/data"] o [{ mountPath: "/data", sizeGb: 20 }]volúmenes
cron"0 3 * * *"programación cron
resources{ cpu: "500m", memory: "1GB" }límites
replicas2réplicas
sleeptrueApp Sleeping
restartPolicy"ON_FAILURE" o { type, maxRetries }política de reinicio

fn(name, config) es un servicio con kind: "function"; combínalo con cron para tareas. empty() significa que el origen se gestiona en otro lugar (el panel) mientras el archivo gestiona la configuración, las variables, los dominios y los volúmenes.

Variables y secretos#

const api = service("api");
service("web", {
  env: {
    DATABASE_URL: db.env.DATABASE_URL,                    // ${{db.DATABASE_URL}}, con tipos
    API_HOST: api.env.SKIFFLY_PRIVATE_DOMAIN,             // variable integrada de otro servicio
    SELF_URL: "https://${{self.SKIFFLY_PUBLIC_DOMAIN}}",  // self = este servicio
    REGION: shared("REGION"),                             // ${{shared.REGION}}
    STRIPE_KEY: preserve(),                               // conserva el valor guardado en Skiffly
    JWT_SECRET: generate("hex64"),                        // aleatorio en el primer apply, luego se conserva
  },
});

skiffly config init escribe los secretos existentes como process.env.NAME ?? preserve(), así que el archivo generado se puede commitear sin riesgo. plan falla si una variable con preserve() todavía no tiene valor en Skiffly.

Bases de datos#

const db = postgres("db", { sizeGb: 20, env: { POSTGRES_DB: "shop" } });
const cache = redis("cache");
const sql = mysql("sql");
const docs = mongo("docs");

Cada una se expande a la plantilla del mismo nombre: imagen, puerto, volumen, contraseña generada y la variable con la cadena de conexión (db.env.DATABASE_URL, cache.env.REDIS_URL, sql.env.MYSQL_URL, docs.env.MONGO_URL). database(name, engine, options) es la forma genérica para otra imagen de un motor conocido.

Entornos en un solo archivo#

export default defineSkiffly((ctx) => {
  const prod = ctx.isEnvironment("production");
  const web = service("web", { replicas: prod ? 2 : 1, resources: { memory: prod ? "2GB" : "512MB" } });
  return project("my-app", { resources: [web] });
});

ctx trae command, projectId, environment, isEnvironment(), randomString() y shared (ctx.shared.NAME referencia una variable compartida).

CI#

.github/workflows/deploy.yml
- run: npx skiffly config apply --yes -p my-app -e production
  env:
    SKIFFLY_TOKEN: ${{ secrets.SKIFFLY_TOKEN }}

Usa un token de espacio de trabajo con el scope write. plan --json produce un diff legible por máquina para comentarios en pull requests.

Diferencias con el SDK de Railway#

  • defineRailwaydefineSkiffly; las variables de plataforma son SKIFFLY_*.
  • Los domains se aplican, no son solo de importación; domain: true gestiona el dominio generado.
  • Los volumes se crean y se eliminan (prune) por ruta de montaje; cambiar el tamaño genera una advertencia.
  • generate() crea secretos en el primer apply; resources, sleep y restartPolicy son opciones propias de Skiffly.
  • No disponible: bucket(), group(), template(), mapas de réplicas multirregión, proxies TCP (usa skiffly proxy).

Referencia completa: el README de @skiffly/config en npm.