Build on Darwa
Darwa runs applications from your repository — web services, static sites, workers, agents, databases, and object storage — without you configuring infrastructure. This reference covers every service, the REST API, and the CLI.
Quickstart
Install the CLI, authenticate, and deploy the repository you are standing in. Darwa detects the framework, writes the build and start commands, and returns a URL.
# 1 — install on macOS brew install haqiq-app/tap/darwa # Alternative: install the release with npm npm i -g https://github.com/haqiq-app/darwa-cli/releases/download/v0.2.0/darwa-cli-0.2.0.tgz # 2 — authenticate (opens a browser) darwa login # 3 — deploy the current directory darwa deploy # 4 — inspect the project darwa projects list
darwa deploy creates the service on first run and updates it after that. Nothing is asked interactively unless detection is ambiguous.
Core concepts
| Concept | Meaning | |
|---|---|---|
| Project | A repository and everything deployed from it. Billing and team access attach here. | |
| Service | One running thing — a web service, static site, worker, or agent. | |
| Environment | development, testing, staging, production, or a temporary preview. Same build, different values. | |
| Release | An immutable build plus its configuration. Rollbacks restore a release. | |
| Resource | A database or storage bucket attached to a project and injected into services. | |
darwa.yaml reference
Detection covers most projects. Commit darwa.yaml when you want the configuration in version control, or when one repository holds several services.
services:
- name: storefront # web service
type: web
runtime: node22
build: npm ci && npm run build
start: npm start
regions: [us-east, eu-central]
scale: { min: 1, max: 8, on: cpu }
- name: image-worker # background worker
type: worker
runtime: node22
start: node worker.js
queue: { name: images, type: priority }
concurrency: 20
retries: { attempts: 5, backoff: exponential }
resources:
- postgres: storefront-db
- bucket: user-uploadsWeb services
A web service is a process that listens for HTTP requests and stays running. It gets adarwa.app subdomain immediately, plus any custom domains you add.
Port binding
Bind to the port in PORT on host 0.0.0.0. If you bind elsewhere, Darwa detects the listening port at build time rather than failing the deploy.
const port = process.env.PORT || 3000;
app.listen(port, "0.0.0.0", () => console.log(`listening on ${port}`));Environment variables
Values are set per environment and injected at runtime. Secrets are never written to build output or logs, and a value matching a stored secret is redacted wherever it appears.
darwa env set DATABASE_URL=... --env production darwa env set LOG_LEVEL=debug --env preview darwa env diff staging production
Scaling rules
| Field | Type | Description |
|---|---|---|
| minrequired | integer | Instances kept running at all times. 0 allows scale to zero. |
| maxrequired | integer | Hard ceiling. Never exceeded, even under a traffic spike. |
| on | enum | cpu | memory | requests | queue_depth. Defaults to cpu. |
| target | integer | Utilisation percentage to hold. Defaults to 70. |
| predictive | boolean | Scale ahead of recurring traffic patterns. Defaults to true on Pro. |
Static websites
Framework, build command, and output directory are read from the project. Node version comes from .nvmrc, package.json, or the latest LTS.
Redirects, rewrites, and headers
{
"redirects": [
{ "from": "/old-page", "to": "/new-page", "status": 301 },
{ "from": "/blog/:slug", "to": "/articles/:slug" }
],
"rewrites": [
{ "from": "/api/*", "to": "https://api.acme.com/*" }
],
"headers": [
{ "for": "/*", "set": { "X-Frame-Options": "DENY" } }
]
}Image optimization
Reference the original path. The response is AVIF or WebP with a JPEG fallback, sized to the request, with a blur placeholder available at ?blur.
<img src="/hero.jpg" width="1600" height="900" alt="…" /> <!-- served as AVIF 188 KB instead of JPEG 4.2 MB -->
Background workers
A worker consumes jobs from a managed, Redis-compatible queue. Existing BullMQ, Celery, Sidekiq, and Asynq code connects with the injected connection string.
import { Worker } from "bullmq";
new Worker("images", async job => {
await resize(job.data.key);
}, { connection: { url: process.env.QUEUE_URL } });Schedules
darwa schedule add nightly-export --cron "0 2 * * *" --overlap skip darwa schedule add health-sweep --every "5 minutes" darwa schedule run nightly-export # trigger once, now
Retries and dead letters
| Field | Type | Description |
|---|---|---|
| attemptsrequired | integer | Total tries including the first. Maximum 25. |
| backoff | enum | fixed | linear | exponential. Defaults to exponential. |
| dead_letter | boolean | Move exhausted jobs to the dead-letter queue. Defaults to true. |
| timeout | duration | Kill and retry a job that exceeds this. Defaults to 15m. |
AI agents
Deploy event-driven or long-running agents with triggers, durable memory, scoped tools, human approval gates, and step-level traces. The full runtime guide now has its own documentation page.
Databases
Creating a database injects DATABASE_URL into the services you select. TLS is required and certificates are managed for you.
darwa db create storefront-db --engine postgres:17 --size standard darwa db url storefront-db --pooled darwa db psql storefront-db # opens a session, no tunnel needed
Connection pooling
Use the pooled URL (:6543) for serverless and worker pools, and the direct URL (:5432) for migrations and anything needing session state.
Prepared statements and LISTEN/NOTIFY require the direct connection. Running migrations through the pooler can fail with transaction-mode errors.
Backups and recovery
darwa db backups storefront-db darwa db restore storefront-db --to "2026-08-02 14:12:09" # restores into a NEW instance; promote it once you have verified it
Cloud storage
Buckets are S3-compatible. Point any existing SDK at the injected endpoint and credentials.
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({
endpoint: process.env.DARWA_STORAGE_ENDPOINT,
region: "eu-central",
});
await s3.send(new PutObjectCommand({
Bucket: "user-uploads",
Key: "2026/06/IMG_4482.jpg",
Body: file,
}));Signed uploads
darwa storage sign user-uploads/2026/06/photo.jpg --put --expires 15m
Semantic search
{
"q": "product images with blue shoes",
"limit": 10,
"filter": { "size_gt": "1MB" }
}{
"results": [
{
"key": "uploads/2026/06/IMG_4482.jpg",
"score": 0.94,
"why": "blue suede trainers on a wooden floor",
"tags": ["shoes", "blue", "product"],
"size": 2411520
}
],
"searched": 1204882,
"took_ms": 310
}Developer interfaces
Use the CLI for terminal workflows and the REST API for applications and automation. Both use the same workspace → project → service → deployment resource model.
Platform agents
Give your own agent scoped access to Darwa so it can deploy, inspect logs, and open pull requests on your behalf. Tokens are scoped by action and by project, and every call an agent makes appears in activity history attributed to that token.
darwa tokens create ci-agent \ --scope deploy:staging,logs:read,metrics:read \ --project storefront --expires 90d
Available tools
| Tool | Scope | What an agent can do |
|---|---|---|
| deploy | deploy:{env} | Trigger a deploy or roll back a release |
| logs | logs:read | Read build and runtime logs, filtered by service |
| metrics | metrics:read | Latency, error rate, saturation, queue depth |
| diagnose | diagnose:read | Fetch the platform's own analysis of a failure |
| env | env:write | Set environment values — never read secret values back |
| db | db:read | Run read-only queries against a nominated database |
Secret values cannot be read through the API at all — an agent may set a value or check that one exists, but never retrieve it. Anything else would make a leaked token a leaked vault.