bext.dev
DocsDeploying
Deploying5 min read
On this page

Infrastructure Generators

bext ships four CLI generators that produce infrastructure config tailored to your project. They read bext.config.toml, detect the framework from ambient file markers (like astro.config.mjs, Gemfile, manage.py), and emit a sensible default that you can commit and edit.

All four generators default to stdout so you can pipe them directly to a file, or pass --out <path> to write the file yourself.

bext dockerfile gen#

Emits a multi-stage Dockerfile tailored to the detected framework.

bash
bext dockerfile gen > Dockerfile
# or
bext dockerfile gen --out Dockerfile

The generated Dockerfile has three stages:

  1. bext-base — the official bext runtime image (ghcr.io/bextdev/bext:latest by default; override with --bext-image)
  2. framework-build — the framework's toolchain: oven/bun:1 for Astro / SvelteKit / SolidStart / Qwik / PRISM, ruby:3.3-slim for Rails, python:3.12-slim for Django, composer:2 + php:8.3-fpm-alpine for Laravel, elixir:1.16-alpine for Phoenix
  3. runtime — final minimal image that copies the build output, sets a HEALTHCHECK against bext health, and runs bext serve

For projects where no framework is detected, the generator skips the framework-build stage and emits a minimal runtime that just copies the project tree and runs bext serve.

Flags#

Flag Default Purpose
--dir <path> . Project root to read
--out <path> stdout Write Dockerfile to this path
--bext-image <tag> ghcr.io/bextdev/bext:latest Override the base image

bext ci gen#

Emits a CI workflow for a supported platform: GitHub Actions (default), GitLab CI, CircleCI, Cloudflare, Fly, and Render.

bash
bext ci gen --platform github > .github/workflows/bext.yml
# with a deploy target
bext ci gen --platform github --deploy-target self-hosted --out .github/workflows/bext.yml
# no deploy step, just build + test
bext ci gen --platform github --deploy-target none

The default GitHub workflow has:

  • A build job that checks out the repo, installs the Rust toolchain, installs bext via the curl-installer, and runs bext check, bext build, and bext test
  • A deploy job that runs only on pushes to main/master, SSHes into DEPLOY_HOST using secrets, and runs bext upgrade + systemctl reload bext

Flags#

Flag Default Purpose
--dir <path> . Project root to read
--platform <name> github CI platform: github, gitlab, circle, cloudflare, fly, render
--deploy-target <kind> self-hosted self-hosted or none
--out <path> stdout Write workflow to this path

bext systemd gen#

Emits a bext.service unit file (and optionally a companion bext.socket unit when --socket-activation is passed).

bash
bext systemd gen > bext.service
# with socket activation
bext systemd gen --socket-activation > units.txt
# custom user + working directory
bext systemd gen --user www-data --working-dir /srv/bext

The output uses a sentinel ### FILE: bext.service header to separate each unit in the stream. Split on that header if you piped both units to a single file.

The default unit uses Type=notify, sets hardening flags (NoNewPrivileges, ProtectSystem=strict, PrivateTmp, PrivateDevices), and restarts on failure with a 2-second back-off.

With --socket-activation, the service gets Requires=bext.socket + Sockets=bext.socket and the socket unit listens on 0.0.0.0:80 + 0.0.0.0:443 with ReusePort=true. This is the shape the zero-downtime binary upgrade path expects — see Zero-Downtime Upgrades.

Flags#

Flag Default Purpose
--dir <path> . Project root to read
--socket-activation off Also emit bext.socket and wire it into the service
--user <user> bext Unix user the service runs as
--working-dir <path> /opt/bext WorkingDirectory for the service
--out <path> stdout Write units to this path

bext export docker-compose#

The reverse of bext import: walk your bext.config.toml and declared plugins, then emit a docker-compose.yaml suitable for local development.

bash
bext export docker-compose > docker-compose.yaml

The bext service is always present. Backend services are auto-added from plugin naming conventions:

Plugin name contains Service added Env var wired
-pg, -postgres, -pgsql postgres:16-alpine DATABASE_URL
-redis redis:7-alpine REDIS_URL
-meili, meilisearch getmeili/meilisearch:v1.7 MEILI_URL

So a project that declares @bext/session-redis and @bext/locking-pg gets both redis and postgres services with the matching env vars wired into the bext service. Volumes and a shared bext-net network are emitted for every backend.

A richer version that reads requires_capabilities from plugin manifests is a wave-2 item; for v1 the naming convention is authoritative.

Flags#

Flag Default Purpose
--dir <path> . Project root to read
--out <path> stdout Write compose to this path
--bext-image <tag> ghcr.io/bextdev/bext:latest Override the image used by the bext service

Regeneration#

All four generators are pure functions of the project state — running them twice produces identical output. Re-run them after bumping bext or adding plugins and commit the diff; that's the intended review loop.

They also have no side effects beyond writing the target file. They never modify bext.config.toml, never fetch anything from the network, and never touch the plugin cache. This makes them safe to run inside CI pipelines, pre-commit hooks, or scripts.

Framework detection#

The generators recognise:

  • Astroastro.config.*
  • SvelteKitsvelte.config.*
  • SolidStartsolid.config.*
  • Qwikqwik.config.*
  • RailsGemfile with a gem 'rails' line
  • Djangomanage.py
  • Laravelcomposer.json with "laravel/framework"
  • Phoenixmix.exs with :phoenix
  • PRISM-shaped TSX project — legacy heuristic: package.json with a "react" dependency and no Next.js marker. React may be present only for a client island; native PRISM rendering does not call React.

Detection is a thin file-marker scan, not a full project parse. If you hit a project the generators misidentify, please open an issue.

Tip

All four generators are pure functions — running them twice produces identical output. Re-run them after bumping bext or adding plugins and commit the diff. This makes them safe inside pre-commit hooks or CI without worrying about side effects.

  • Zero-Downtime Upgrades — the systemd unit generated by bext systemd gen --socket-activation is the recommended shape for the upgrade signal flow
  • Scalingbext export docker-compose wires Redis and Postgres from plugin names; see the scaling page for Redis L2 cache config
  • Configuration: Docker — Docker-specific runtime configuration that complements the generated Dockerfile
  • Configuration: bext.config.toml — the config file the generators read to tailor their output
  • Frameworks: Overview — framework detection markers match the frameworks listed here
Edit this page ↗Need a hand? ↗
FIND YOUR NEXT STEP

Start with a topic, a command, or a question.