DevStack is a Rust CLI that generates a complete local backend development environment in one command.
Think of it like create-next-app, but for backend infrastructure and service foundations. Instead of spending hours wiring together Docker, Postgres, Redis, workers, nginx, environment files, and CI from scratch, you run one command and start building the actual product.
Starting a backend project usually means repeating the same setup work:
- Create a service skeleton
- Add Docker and Compose
- Add Postgres and Redis
- Add worker processes
- Add nginx
- Add environment files
- Add CI
- Add a sane folder layout
That work is important, but it is also repetitive. DevStack turns that setup into a single command and gives developers a base they can keep, understand, and extend.
DevStack currently supports:
nodedjangoflaskfastapi
Each generated project includes:
- Dockerized app runtime
compose.yaml- Postgres with persistent storage
- Redis
- nginx reverse proxy
- Background worker service
- Background beat scheduler for Python stacks
.envand.env.exampleMakefile- GitHub Actions CI
- A production-minded starter layout
Run the generator with Cargo:
cargo run -- init djangoYou can generate any supported stack:
cargo run -- init node
cargo run -- init django
cargo run -- init flask
cargo run -- init fastapiYou can also provide a custom project name:
cargo run -- init fastapi my-payments-apiOr choose the target directory explicitly:
cargo run -- init flask --dir /tmp/my-flask-serviceIf the destination already exists and you want to allow generation there:
cargo run -- init node my-service --dir ./my-service --forceCurrent command shape:
devstack init <stack> [name] [--dir <path>] [--force]Arguments:
<stack>: one ofnode,django,flask, orfastapi[name]: optional project name; if omitted, DevStack uses a stack-specific default--dir <path>: optional output directory--force: allows writing into an existing non-empty target directory
Default names:
node->node-servicedjango->django-serviceflask->flask-servicefastapi->fastapi-service
The exact generated app code differs by stack, but the overall output looks like this:
your-project/
├── .env
├── .env.example
├── .dockerignore
├── .gitignore
├── Makefile
├── README.md
├── compose.yaml
├── .github/
│ └── workflows/
│ └── ci.yml
├── docker/
│ ├── Dockerfile
│ ├── start.sh
│ ├── worker.sh
│ └── beat.sh # Python stacks only
├── nginx/
│ └── default.conf
└── app/
└── ... stack-specific application files ...
Every generated project includes:
-
compose.yamlBrings up the app, worker processes, nginx, Postgres, and Redis. -
.envand.env.exampleContains app name, port, database credentials, Redis URLs, and Celery settings for Python stacks. -
MakefileConvenience commands for common local tasks such as starting the stack, viewing logs, and opening shells. -
.github/workflows/ci.ymlA basic CI workflow that validates the generated service and container setup. -
nginx/default.confReverse proxy configuration for routing traffic to the generated app container.
The Node generator creates:
- Express HTTP service
- BullMQ-backed worker setup
- Redis queue connection
- Postgres connection wiring
- Node-specific Docker image and scripts
Generated Node app highlights:
app/src/index.jsapp/src/queue.jsapp/src/worker.jsapp/package.json
The Django generator creates:
- Django app configuration
- Django health and readiness endpoints
- Postgres database settings
- Redis-backed Celery worker and beat setup
- Core routes and tasks
Generated Django app highlights:
app/manage.pyapp/config/settings.pyapp/config/urls.pyapp/config/celery.pyapp/core/views.pyapp/core/tasks.py
The Flask generator creates:
- Flask application factory
- Gunicorn startup path
- Postgres and Redis configuration
- Celery worker and beat setup
- HTTP endpoints for health, readiness, and sample job enqueueing
Generated Flask app highlights:
app/app/__init__.pyapp/app/config.pyapp/app/routes.pyapp/app/celery_app.pyapp/app/tasks.pyapp/app/wsgi.py
The FastAPI generator creates:
- FastAPI application
- Uvicorn startup path
- Postgres and Redis integration
- Celery worker and beat setup
- HTTP endpoints for health, readiness, and job enqueueing
Generated FastAPI app highlights:
app/app/main.pyapp/app/config.pyapp/app/worker.py
Once a project has been generated:
cd your-project
docker compose up --buildThen visit:
http://localhost
Most generated projects also include:
/healthz/readyz/jobs/ping
These endpoints make it easier to test local readiness and background job wiring immediately after setup.
This repository is intentionally split so contributors can work on one concern at a time.
src/
├── main.rs
├── lib.rs
├── cli.rs
├── project.rs
└── generator/
├── mod.rs
├── common.rs
├── shared.rs
└── stacks/
├── mod.rs
├── node.rs
├── django.rs
├── flask.rs
└── fastapi.rs
-
src/main.rsThin binary entrypoint. -
src/lib.rsTop-level library surface that delegates to the CLI. -
src/cli.rsCLI parsing and command dispatch usingclap. -
src/project.rsShared domain types such asStack,Project, andFileEntry. -
src/generator/mod.rsMain orchestration for project generation. -
src/generator/common.rsShared low-level helpers for name sanitization, target directory resolution, validation, and file writing. -
src/generator/shared.rsCross-stack templates and reusable generated files such as env files, compose config, CI config, nginx config, and shared Docker helpers. -
src/generator/stacks/*.rsOne module per supported stack. Each module owns only the files and templates unique to that stack.
The codebase follows a few straightforward rules:
- Keep the binary entrypoint tiny
- Keep CLI parsing separate from generation logic
- Keep shared infrastructure templates centralized
- Keep stack-specific templates isolated per language/framework
- Prefer explicit string templates over over-abstracted code generation
- Keep adding a new stack predictable
This structure makes the project easier to review, easier to extend, and easier to contribute to without stepping on unrelated work.
To work on DevStack itself, you need:
- Rust
- Cargo
If you want to run generated projects locally, you should also have:
- Docker
- Docker Compose
Format the code:
cargo fmtRun tests:
cargo testGenerate a sample project locally:
cargo run -- init djangoGenerate into a throwaway directory:
cargo run -- init node --dir /tmp/devstack-node-smokeAdding a new stack should be boring and mechanical.
- Add the new variant to
Stackin src/project.rs. - Define stack-specific metadata such as label, default name, and port.
- Create a new stack module in
src/generator/stacks/. - Return that stack's file set from
src/generator/stacks/mod.rs. - Reuse shared templates from
src/generator/shared.rswherever possible. - Keep only stack-unique files in the new stack module.
- Add tests or smoke checks as needed.
The intended pattern is:
- Shared behavior belongs in
common.rsorshared.rs - Stack-specific output belongs in that stack's module
- Cross-cutting domain metadata belongs in
project.rs
If you want to contribute, a few conventions will keep the project clean:
- Do not move stack-specific templates into shared modules unless multiple stacks truly use them
- Do not add new stacks by expanding a single giant file
- Keep generated file paths explicit and readable
- Prefer simple helpers over clever abstractions
- Preserve the current structure where contributors can reason stack by stack
Good contribution areas:
- Add new stacks
- Improve generated project quality
- Improve CI templates
- Improve Docker ergonomics
- Add better health or production defaults
- Add tests around generation output
- Add richer CLI features
A few details about the current implementation:
- The CLI uses
clap - Error handling uses
anyhow - Generated Python stacks share a common Python Dockerfile
- Generated Node stacks use a Node-specific Dockerfile and
node_modulesvolume - Python stacks generate both a worker and a beat service
- Node currently generates a worker service but not a beat scheduler
cargo run -- init django billing-platform
cd billing-platform
docker compose up --buildcargo run -- init node api-gateway --dir ./sandbox/api-gateway
cd ./sandbox/api-gateway
docker compose up --buildcargo run -- init fastapi payments --dir ./services/payments --forceSome obvious future directions:
- More stacks such as Rails, Go, Laravel, NestJS, or Spring Boot
- Template versioning
- Optional flags for skipping Redis or nginx
- Optional test scaffolding
- Optional observability stack
- Better production deployment presets
- Snapshot-style tests for generated output
DevStack is not just about generating files. It is about making backend setup feel lightweight, understandable, and maintainable.
That means the generator itself has to be maintainable too. The codebase is structured so that:
- people can review one stack in isolation
- contributors can add features without touching everything
- shared behavior stays DRY
- generated output remains explicit rather than magical
That tradeoff is intentional.