Develop with Docker Compose
Build and run staqly from a checkout with Docker Compose, the development stack and the test suites.
This page is for working on staqly itself. To just run staqly, use the binary or the Docker image: neither needs this repository.
Start from a checkout
git clone https://github.com/staqly/staqly.git && cd staqly
make devYou need Docker with Compose v2, make, and for the tests Node (.nvmrc), pnpm and Go.
make dev builds the image from your checkout, starts the development stack,
waits until it is healthy and opens the dashboard in your browser, already signed in.
Make targets
| Command | Does |
|---|---|
make dev | Builds the image from your checkout and starts the development stack |
make dev-down | Stops the development stack (the data volume is kept) |
make up | Starts compose.yml alone with the released image (STAQLY_VERSION, default latest), building it if the pull fails |
make build / make pull | Builds the image from your checkout / downloads the released one, without starting anything |
make open / make connect / make token | Opens this computer's browser signed in / prints a one-time sign-in link for another browser / prints the access token (ROTATE=1 makes a new one) |
make down, make logs, make ps | Stops the stack, follows its logs, shows its status |
make seed | Loads demo data through the API (scripts/seed.sh) |
make backup / make restore BACKUP=backups/<timestamp> | scripts/backup.sh / scripts/restore.sh: the Docker backup and restore steps for the Compose volume |
make mcp-stdio | docker exec -i staqly mcp-stdio; see the operator commands |
make site | Runs the landing page (http://localhost:8070) and these docs (http://localhost:8090) from your checkout, with hot reload. They are static sites and never run in Docker |
make help | Lists every target |
Don't use docker compose down -v
-v deletes the data volume — your database and uploads. Plain docker compose down
(or make down) is safe.
Compose files
| File | Used by | What it adds |
|---|---|---|
compose.yml | everything | The staqly service (container staqly, image ghcr.io/staqly/staqly:${STAQLY_VERSION:-latest}, build context .) with the same ports and hardening as the docker run command, and the volume staqly-data (Compose names it staqly_staqly-data). On the Compose network it is also reachable as api (http://api:3333). |
compose.dev.yml | make dev | The development stack |
compose.e2e.yml | pnpm test:e2e | An isolated staqly-e2e project on other ports |
Settings go in .env in the repository root (copy .env.example); Compose passes most of them
to the container. Apply changes with docker compose up -d. Memory and process limits are
STAQLY_MEM_LIMIT (default 640m) and STAQLY_PIDS_LIMIT (default 256).
Development stack
make dev runs compose.yml plus compose.dev.yml, with the image built from your checkout.
Compared with compose.yml alone it:
- logs at
debuglevel intextformat, - lets webhooks, schedule endpoints and alerts reach private addresses (
WEBHOOK_ALLOW_PRIVATEandNOTIFY_ALLOW_PRIVATEdefault totrue), so they can reach mailpit, n8n or your own receivers on the Docker network, - sets
COOKIE_SECURE=falseandPUBLIC_DASHBOARD_URL=http://localhost:8080(or yourDASHBOARD_PORT) by default, - adds mailpit (
staqly-mailpit), which catches every email alert. Open its inbox athttp://localhost:8025(MAILPIT_PORTchanges the port). In an email alert use hostmailpit, port1025, TLSnone, - adds MaxIOFS (
staqly-maxiofs, an S3-compatible server) and keeps media files there, the way a production server keeps them in AWS S3 or another S3-compatible bucket. The S3 API answers athttp://localhost:9000, the web console athttp://localhost:9001(admin/admin;MAXIOFS_PORTandMAXIOFS_CONSOLE_PORTchange the ports). The bucketstaqly-mediaand a development-only access key are created on first start; the files live in thestaqly-maxiofsvolume.STORAGE_DRIVER=diskin.envkeeps them in the data volume instead. See Media storage.
Every value above can still be overridden in .env. Stop the stack with make dev-down.
compose.yml alone (docker compose up -d --build) builds the same image without the extras.
Images and releases
The image is built from the Dockerfile in the repository root and published to GitHub
Container Registry as ghcr.io/staqly/staqly, for linux/amd64 and linux/arm64. A maintainer
publishes a release with make release VERSION=v0.2.0: it tags origin/main (only if CI on that
commit passed), and the tag makes CI publish the binaries and the image as v0.2.0 and latest.
To build the image by hand: docker build -t staqly .
Running from source without Docker
For working on staqly itself (to just run it without Docker, use the binary):
pnpm install # once, in the repository root
cd apps/api && go run ./cmd/server # Community Edition, data in ./data, listens on 127.0.0.1:3333
pnpm --filter @staqly/platform dev # dashboard (Next.js dev server); API_INTERNAL_URL defaults to http://localhost:3333The repository is a Turborepo with pnpm workspaces. The dashboard lives in apps/platform; the
landing page (staqly.ai) is apps/web and the docs site apps/docs. Useful commands from the
repository root:
| Command | Does |
|---|---|
make check (pnpm check) | Formatting, lint, types and unit tests of every package |
make test (pnpm test) | Unit and integration tests of every package |
make test-api, make test-cli, make test-dashboard, make test-sdk, make test-sdk-python | Tests of one package (pnpm turbo run test --filter=@staqly/<name>) |
make test-e2e (pnpm test:e2e) | End-to-end suite in e2e/: builds the image, starts an isolated staqly-e2e compose project (compose.yml + compose.e2e.yml, ports 13333, 18080 and 19000) and runs Vitest tests with the TypeScript SDK against it. E2E_KEEP=1 leaves the stack running, E2E_BUILD=0 reuses the built image |
make gen (pnpm gen) | Regenerates the sqlc queries, the dashboard API types and the TypeScript SDK schema |
make lint-openapi | Validates apps/api/openapi.yaml |
make dashboard | Builds the static dashboard into apps/api/web, so the Go binaries embed it |
Outside Docker too, every request needs the access token (go run ./cmd/server prints it at start,
go run ./cmd/server token prints it again). Add WEBHOOK_ALLOW_LOOPBACK=true when webhook
receivers listen on localhost.
n8n
n8n is not part of the stack. Use your own, or the example next to staqly:
docker compose -f integrations/n8n/compose.yml up -d — see n8n.