Every Shaperail project has a single configuration file named shaperail.config.yaml in the project root. This file defines the project configuration surface for the generated app and optional runtime features.

Minimal config

The only required field is project:

project: my-app

With nothing else specified, the server starts on port 3000 with automatic worker detection and no database, cache, or auth.

Full annotated example

project: my-api
port: 8080
workers: 4

databases:
  default:
    engine: postgres
    # `.env` sets DATABASE_URL, which overrides the fallback below.
    # Edit `.env` (not this file) for local connection strings.
    url: ${DATABASE_URL:postgresql://localhost/my_api_db}
    pool_size: 20

cache:
  type: redis
  url: redis://${REDIS_HOST:localhost}:6379

auth:
  provider: jwt
  secret_env: JWT_SECRET
  expiry: 24h
  refresh_expiry: 30d

storage:
  provider: s3
  bucket: my-bucket
  region: us-east-1

logging:
  level: info
  format: json
  otlp_endpoint: http://localhost:4317

events:
  subscribers:
    - event: "user.created"
      targets:
        - type: webhook
          url: "https://example.com/hooks/user-created"
        - type: job
          name: send_welcome_email
        - type: channel
          name: notifications
          room: "org:{org_id}"
        - type: hook
          name: validate_org
  webhooks:
    secret_env: WEBHOOK_SECRET
    timeout_secs: 30
    max_retries: 3
  inbound:
    - path: /webhooks/stripe
      secret_env: STRIPE_WEBHOOK_SECRET
      events: ["payment.completed", "subscription.updated"]

Section reference

project

Field Type Required Default Description
project string yes Project name. Used for logging, Docker image tags, and the generated crate name.

port

Field Type Required Default Description
port integer no 3000 TCP port the HTTP server binds to.

workers

Field Type Required Default Description
workers "auto" or integer no auto Number of Actix-web worker threads. auto uses the number of CPU cores.

protocols (M15/M16)

Optional. List of API protocols to enable. When omitted, defaults to ["rest"].

protocols:
  - rest
  - graphql
  - grpc
Value Description
rest REST API (list, get, create, update, delete) — always available when a database is configured.
graphql GraphQL endpoint at /graphql and Playground at /graphql/playground. Current list fields expose limit and offset; see the GraphQL guide.
grpc gRPC server on a separate port (default 50051). Current runtime support covers list/stream/get/create/delete plus health/reflection; see the gRPC guide.

Only rest, graphql, and grpc are allowed. Unknown values cause a parse error.

graphql (M15)

Optional. Configures GraphQL depth and complexity limits. Only relevant when graphql is in protocols.

graphql:
  depth_limit: 10
  complexity_limit: 200
Field Type Default Description
depth_limit integer 16 Maximum query nesting depth. Queries exceeding this depth are rejected.
complexity_limit integer 256 Maximum query complexity score. Queries exceeding this are rejected.

grpc (M16)

Optional. Configures the gRPC server. Only relevant when grpc is in protocols.

grpc:
  port: 50051
  reflection: true
Field Type Default Description
port integer 50051 Port for the gRPC server. Separate from the HTTP port.
reflection boolean true Enable gRPC server reflection for tools like grpcurl.

databases

Migrating from v0.10: The legacy singular database: block was removed in v0.11. Configs containing it now fail to parse with unknown field 'database'. Replace the block with databases.default: as shown below.

Optional. Named database connections. Every new project scaffolded by shaperail init uses this form. When omitted, no database pool is created.

The recommended form (also what shaperail init now generates):

databases:
  default:
    engine: postgres
    # `.env` sets DATABASE_URL, which overrides the fallback below.
    # Edit `.env` (not this file) for local connection strings.
    url: ${DATABASE_URL:postgresql://localhost/<project>}
    pool_size: 20

You must include a connection named default; migrations run against the default connection. Use ${VAR} or ${VAR:default} in URLs for environment variable interpolation.

For multi-database setups, add additional named connections:

databases:
  default:
    engine: postgres
    url: ${DATABASE_URL}
    pool_size: 20
  analytics:
    engine: postgres
    url: postgres://user:pass@analytics-db.example.com/analytics
    pool_size: 10

databases — connection options

Optional. Named database connections for multi-database projects. When set, the server uses an ORM-backed store and routes each resource to the connection named by its db: key (or default when omitted).

You must include a connection named default; migrations run against the default connection. Use ${VAR} or ${VAR:default} in URLs for environment variable interpolation.

databases:
  default:
    engine: postgres
    url: ${DATABASE_URL}
    pool_size: 20
  analytics:
    engine: postgres
    url: postgres://user:pass@analytics-db.example.com/analytics
    pool_size: 10
Field Type Required Default Description
name object yes Connection name (e.g. default, analytics). Resources select via db: <name>.
engine string yes One of: postgres, mysql, sqlite.
url string yes Connection URL (e.g. postgres://..., mysql://..., file:data.db).
pool_size integer no 20 Maximum connections in the pool for this database.

Supported engines:

  • postgres — PostgreSQL. Full CRUD, filters, sort, pagination, migrations.
  • mysql — SQL multi-db support is wired in the runtime and scaffold bootstrap.
  • sqlite — SQL multi-db support is wired in the runtime and scaffold bootstrap.

MongoDB note: the core multi-db model also includes a mongodb engine and the runtime exposes Mongo-backed store primitives behind the multi-db feature, but the scaffolded bootstrap only wires SQL engines automatically today.

When databases is present, database is ignored and DATABASE_URL is only used if you reference it inside a databases.*.url value (e.g. default).

cache

Optional. When omitted, no Redis connection is created.

Field Type Required Default Description
type string yes Cache backend. Use redis.
url string yes Redis connection URL (e.g., redis://localhost:6379).

auth

Optional. When omitted, endpoints that declare auth will fail validation.

Field Type Required Default Description
provider string yes Auth strategy. Use jwt.
secret_env string yes Name of the environment variable holding the signing secret.
expiry string yes Token lifetime (e.g., 24h, 60m).
refresh_expiry string no Refresh token lifetime (e.g., 30d). Omit to disable refresh tokens.

Current limitation: the scaffolded app currently reads JWT settings from the JWT_SECRET environment variable only and uses built-in 24h / 30d defaults. The auth: block is parsed and validated, but the generated bootstrap does not yet consume secret_env, expiry, or refresh_expiry automatically.

storage

Optional. When omitted, file upload endpoints are unavailable.

Field Type Required Default Description
provider string yes Storage backend: s3, gcs, or local.
bucket string no Bucket or container name. Required for s3 and gcs.
region string no Cloud region (e.g., us-east-1). Required for s3.

logging

Optional. Defaults to info-level JSON logs with no OTLP export.

Field Type Required Default Description
level string no info Log level: debug, info, warn, or error.
format string no json Output format: json or pretty.
otlp_endpoint string no OpenTelemetry collector endpoint (e.g., http://localhost:4317). Omit to disable trace export.

events

Optional. Controls event subscribers, outbound webhook settings, and inbound webhook declarations.

Current limitation: the generated scaffold creates an EventEmitter, but it does not automatically start worker handlers for subscriber targets or register inbound webhook routes.

events.subscribers

A list of event routing rules. Each entry maps an event name to one or more targets.

events:
  subscribers:
    - event: "user.created"
      targets:
        - type: job
          name: send_welcome_email
        - type: webhook
          url: "https://example.com/hooks/user-created"
        - type: channel
          name: notifications
          room: "org:{org_id}"
        - type: hook
          name: validate_org
Field Type Required Description
event string yes Event name pattern (e.g., user.created, *.deleted).
targets list yes One or more dispatch targets.

Each target has a type field that determines the remaining fields:

Target type Fields Description
job name Enqueue a background job by name.
webhook url POST to an external URL.
channel name, room (optional) Broadcast to a WebSocket channel. room scopes the broadcast.
hook name Execute a server-side event handler function by name.

Note: the hook event target type in subscriber configuration is separate from endpoint-level business logic. For synchronous request-lifecycle logic (input validation, response enrichment), use controller: on endpoints — see Controllers.

events.webhooks

Global settings for outbound webhook delivery helpers.

Field Type Required Default Description
secret_env string no WEBHOOK_SECRET Environment variable holding the HMAC signing secret.
timeout_secs integer no 30 HTTP timeout in seconds per delivery attempt.
max_retries integer no 3 Maximum retry attempts for failed deliveries.

events.inbound

A list of inbound webhook endpoints for shaperail_runtime::events::configure_inbound_routes(...).

Field Type Required Description
path string yes URL path (e.g., /webhooks/stripe).
secret_env string yes Environment variable holding the verification secret.
events list of strings no Event names this endpoint accepts. Empty means all events.

These entries are parsed by the config layer, but the scaffolded app does not call the inbound-route helper automatically.

Environment variable interpolation

Use ${VAR} to inject an environment variable at parse time. Use ${VAR:default} to provide a fallback when the variable is unset.

project: ${APP_NAME:my-app}
databases:
  default:
    engine: postgres
    url: ${DATABASE_URL:postgresql://localhost/${DB_NAME}}
    pool_size: 20

Rules:

  • ${DB_NAME} – if DB_NAME is not set, the parser returns an error naming the missing variable.
  • ${DB_HOST:localhost} – if DB_HOST is not set, localhost is used.
  • ${} – empty placeholders are rejected.
  • Unterminated ${... without a closing } is rejected.

Interpolation happens before YAML parsing, so the substituted value becomes part of the raw YAML text.

Workspace configuration (M17)

Multi-service projects use shaperail.workspace.yaml instead of (or alongside) the per-service shaperail.config.yaml. See Multi-service workspaces for the full format reference, including service definitions, shared config, and saga files.

Validation rules

Shaperail rejects invalid configuration at startup with a clear error message.

  • project is required. Omitting it produces a “missing field” error.
  • Unknown fields are rejected. Every section uses deny_unknown_fields. A typo like databse: instead of databases: produces an “unknown field” error listing the valid alternatives.
  • Type mismatches fail. Setting port: "not-a-number" or workers: [] produces a deserialization error.
  • Missing env vars fail. A ${VAR} reference with no default and no matching environment variable halts parsing with a message naming the variable.

Back to top

Shaperail documentation lives in the same repository as the framework so every release has versioned instructions. See the latest release for the most recent version.

This site uses Just the Docs, a documentation theme for Jekyll.