Skip to main content
Feather deploys as a Docker image behind Caddy, on one machine. The same Dockerfile also deploys unchanged to Appentic, if you’d rather not run the server yourself. A €7/month VPS runs the app, Postgres, Redis and TLS termination with room to spare, in eight files. feather new scaffolds them. To add them to an existing app:
It inspects your project to decide what to generate, adding a db service if you have a database, and redis and a worker if you use background jobs. It never overwrites an existing file without --force.

What gets generated

The web target is last in the Dockerfile, so a plain docker build . produces the web image. The worker is docker build --target worker .. Both come from one Dockerfile and share a layer cache.

Two details that are easy to break

The frontend stage copies the framework’s templates out of that layer, and Tailwind scans them for the class names the built-in components use.Remove that copy and every framework component renders unstyled in production.
Two web containers starting at once would race on feather db upgrade. deploy/deploy.sh runs them exactly once, in a throwaway container, before any long-lived container starts.

Local development

Your app stays on your machine so feather dev keeps Vite’s hot reload. Only the dependencies run in containers.
Ports and credentials match the DATABASE_URL and REDIS_URL in the generated .env, so nothing else needs configuring. Bring up one service with docker compose -f docker-compose.dev.yml up -d db. Stop them with down, adding -v to discard the local data. To check the production image locally:

Next: first deploy to a VPS

DNS, a deploy user, .env on the server, and the deploy script.