This repository contains 80+ example applications demonstrating how to deploy with Defang. Each sample is a self-contained project showing a specific framework, language, or integration pattern deployed via Docker Compose.
samples/ <- Root
├── samples/ <- All sample projects live here
│ ├── flask/ <- Example: simple Flask app
│ ├── nextjs/ <- Example: Next.js app
│ ├── django-postgres/ <- Example: multi-service with DB
│ └── ... <- 80+ samples total
├── starter-sample/ <- Template used by `new-sample` script
├── scripts/ <- Tooling (new-sample, validation, list generation)
├── templates/ <- GitHub Actions deploy workflow template
├── tools/testing/ <- Go-based load test tool for CI deploy testing
├── .github/workflows/ <- CI workflows
├── README.md <- Auto-generated samples table
└── .gitignore <- Ignores `.defang/` directories
samples/-- Every sample lives in its own kebab-case subdirectory here. Never place samples at the repo root.starter-sample/-- The scaffold copied by. ./scripts/new-sample. Containscompose.yaml,compose.dev.yaml,README.md,.devcontainer/, and.github/workflows/defang.yamlwith#REMOVE_ME_AFTER_EDITINGmarkers.scripts/-- Automation scripts (Node.js). Runnpm ciin this directory before using.templates/defang.yaml-- The canonical deploy workflow. Each sample gets a copy managed bytemplate-manager.js(do NOT manually create or editsamples/*/.github/workflows/defang.yaml).tools/testing/-- Go load test tool used by CI to deploy changed samples to staging and verify they come up healthy.
Every sample MUST contain:
The Docker Compose file that Defang uses to deploy the application.
Conventions:
- The top-level
name:field MUST match the sample's directory name (e.g.,name: flaskforsamples/flask/) - Use
mode: ingressfor user-facing HTTP ports - Use
mode: hostfor internal-only ports (e.g., databases) - Include a
healthcheckfor services with published ports (usecurl,wget, or language-native checks) - Include
deploy.resources.reservationsto specify CPU and memory - Use
restart: unless-stoppedfor long-running services - Secrets go in
environment:with no value (e.g.,POSTGRES_PASSWORD:) so Defang prompts for them viadefang config set - Use
x-defang-postgres: trueon Postgres services for Defang managed Postgres - Source code typically lives in a subdirectory (e.g.,
./app,./flask) with thebuild.contextpointing there
Example:
name: my-sample
services:
app:
restart: unless-stopped
build:
context: ./app
dockerfile: Dockerfile
ports:
- target: 3000
published: 3000
mode: ingress
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/"]
deploy:
resources:
reservations:
cpus: "0.5"
memory: 256MMust follow the established template structure:
# Sample Title
[](https://portal.defang.dev/redirect?url=https%3A%2F%2Fgithub.com%2Fnew%3Ftemplate_name%3Dsample-<DIRNAME>-template%26template_owner%3DDefangSamples)
Description of what this sample does.
## Prerequisites
1. Download [Defang CLI](https://github.com/DefangLabs/defang)
2. (Optional) If you are using [Defang BYOC](https://docs.defang.io/docs/concepts/defang-byoc) authenticate with your cloud provider account
3. (Optional for local development) [Docker CLI](https://docs.docker.com/engine/install/)
## Development
...
## Configuration
...
## Deployment
> [!NOTE]
> Download [Defang CLI](https://github.com/DefangLabs/defang)
### Defang Playground
...
### BYOC (AWS)
...
---
Title: Human-Readable Title
Short Description: One or two sentences.
Tags: Framework, Tool, Category
Languages: python, nodejs, golang, etc.Required metadata fields (at the bottom, after ---):
Title:-- Used in the auto-generated samples tableShort Description:-- One-line summaryTags:-- Comma-separated; frameworks, tools, categories (NOT programming languages)Languages:-- Comma-separated programming languages/runtimes
The 1-click deploy badge URL must use sample-<DIRNAME>-template as the template_name (this is auto-managed by template-manager.js).
Application source code in a subdirectory (commonly app/, or named after the framework like flask/). Must include a Dockerfile unless using a pre-built image.
For local development with hot-reload and local dependencies (like a local MongoDB). Should use extends to inherit from compose.yaml.
Devcontainer config for GitHub Codespaces / VS Code. The starter includes the Defang CLI feature, Docker-in-Docker, and AWS CLI.
Do NOT create this manually. It is generated from templates/defang.yaml by template-manager.js during CI. Pulumi samples are an exception and may have custom workflows.
- From the repo root, run:
. ./scripts/new-sample - Enter a kebab-case name (e.g.,
express-redis) - The script copies
starter-sample/tosamples/<name>/ - Search for
#REMOVE_ME_AFTER_EDITINGin the new directory and update/remove every marked section - Ensure
compose.yamlhasname: <your-sample-name>matching the directory name - Write your application code in the source subdirectory
- Add a proper
Dockerfile - Update the README metadata fields (
Title,Short Description,Tags,Languages) - If the sample needs secrets/config values, add them to
deploy-changed-samples.ymlwithTEST_prefix and set them in repo secrets - Test locally:
docker compose up --build - Test with Defang:
defang compose up - Run the validation script:
./scripts/check-sample-files.sh - Update the samples table:
node scripts/generate-samples-list.js
| Workflow | File | What it does |
|---|---|---|
| Check Samples | check-sample.yml |
Validates compose files, checks README metadata, flags #REMOVE_ME_AFTER_EDITING, manages template repos |
| Deploy Changed Samples | deploy-changed-samples.yml |
Deploys changed samples to Defang staging using the Go load test tool, verifies they come up healthy |
| Build Samples JSON | build-samples-json.yml |
Lints JS/TS files, triggers defang-docs rebuild |
| Test Scripts | test-scripts.yml |
Runs npm test on the scripts package, previews workflow changes |
- Validate structure:
./scripts/check-sample-files.sh - Build locally:
docker compose -f samples/<name>/compose.yaml up --build - Deploy to playground:
cd samples/<name> && defang compose up - Generate samples list:
node scripts/generate-samples-list.js
If your sample requires secrets (e.g., API_KEY):
- Add
TEST_API_KEY: ${{ secrets.TEST_API_KEY }}to the env section ofdeploy-changed-samples.yml - Set
TEST_API_KEYin the repository secrets
The test tool automatically strips the TEST_ prefix and passes the values as Defang config.
- Sample directories: kebab-case (e.g.,
fastapi-postgres,nextjs-blog) - Compose service names: lowercase, short (e.g.,
app,db,api,web)
- Use
depends_onfor service ordering - Use
mode: hostfor inter-service ports (databases) - Use
mode: ingressonly for user-facing HTTP endpoints - Reference other services by their compose service name in environment variables (e.g.,
DB_HOST=db)
- Python: Use
requirements.txt, Flask/FastAPI/Django; healthcheck withpython3 -c "import urllib..." - Node.js/TypeScript: Use
package.json; healthcheck withwget -q --spiderorcurl -f - Go: Standard
go.mod; healthcheck withcurlorwget - Rust: Use
Cargo.toml; healthcheck withcurl - Multi-language: Use separate directories per service, each with its own Dockerfile
x-defang-postgres: true-- Use Defang managed Postgresx-defang-static-files-- Static file serving extension- Pulumi samples use
Pulumi.yamlinstead of (or alongside)compose.yaml
- No
.envfiles with real secrets - No
node_modules/,__pycache__/, build artifacts - No
.defang/directory (already in.gitignore) - No manually created
.github/workflows/defang.yaml(auto-generated from template)
When running inside SAM (detected by $SAM_WORKSPACE_ID environment variable):
- SAM environments are ephemeral -- push changes frequently to avoid losing work
- The Defang CLI may or may not be installed; do not assume it is available for testing
- Push often -- Commit and push after completing each meaningful unit of work
- Report progress -- Use
update_task_statusat milestones:- After creating a new sample scaffold
- After completing the compose.yaml
- After writing the README
- After validating with
check-sample-files.sh
- Capture ideas -- Use
create_ideafor new sample ideas discovered during work (e.g., "sample for Framework X with Database Y") - Search context -- Use
search_messagesto find prior conversations about sample conventions or specific frameworks
SAM maintains a persistent knowledge graph across sessions. Use it to preserve non-obvious context:
add_knowledge— Store observations about:- User preferences and work style (entityType:
preference) - Sample conventions not captured in CLAUDE.md (entityType:
style) - Project context: feature launches, deprecations, new framework support (entityType:
context)
- User preferences and work style (entityType:
search_knowledge— Query before key decisions (e.g., search "PlaygroundDeprecation" before referencing Playground, search "ContentStyle" before writing sample READMEs)update_knowledge/remove_knowledge— Fix stale or incorrect observationsconfirm_knowledge— When you verify an existing observation is still accurate
Do NOT store: patterns derivable from existing samples, git history, ephemeral task details, or anything already in CLAUDE.md.
- Samples MUST use current Defang CLI syntax and features -- check the latest Defang docs if unsure about command syntax
- Use
defang compose up(not deprecated alternatives) - Use
defang config setfor secrets (not environment files) - The deploy workflow uses
DefangLabs/defang-github-action@v1.4.0
# Create a new sample
. ./scripts/new-sample
# Validate all samples
./scripts/check-sample-files.sh
# Regenerate the samples table in README.md
node scripts/generate-samples-list.js
# Test a sample locally
docker compose -f samples/<name>/compose.yaml up --build
# Deploy a sample to Defang Playground
cd samples/<name> && defang compose up
# Install script dependencies (needed for generate/template scripts)
cd scripts && npm ciWhen submitting a new or modified sample:
-
compose.yamlhasname:matching directory name -
compose.yamlpassesdefang compose configvalidation - README has all four metadata fields (
Title,Short Description,Tags,Languages) - No
#REMOVE_ME_AFTER_EDITINGmarkers remain - No
.github/workflows/defang.yamlmanually added (auto-generated) - Sample builds and runs locally with
docker compose up --build - Config values added to
deploy-changed-samples.ymlif secrets are needed -
node scripts/generate-samples-list.jsrun if README metadata changed