One 12MB binary. A whole server stack.
Duso is a scripting language and server runtime in a single Go binary. HTTP server, ACID datastore, WebSockets, AI clients, image processing, a debugger, a linter, even the documentation — all built in. No npm. No virtualenv. No stack to assemble before you can write line one. And it idles at about 5MB of RAM, so it runs happily on the cheapest VPS you can rent.
duso eval 'http_server().start()'That's a web server. It's already running on http://localhost:8080.
Pre-built binaries: duso.rocks/download
Or install with Homebrew:
brew install duso-org/duso/dusoOr build from source:
Linux & macOS:
git clone https://github.com/duso-org/duso.git
cd duso
./build.shWindows PowerShell:
git clone https://github.com/duso-org/duso.git
cd duso
.\build.ps1Then optionally symlink it (Linux & macOS):
ln -s $(pwd)/bin/duso /usr/local/bin/dusoThere's no async/await. Duso doesn't have colored functions. fetch() just returns the response. When you actually want concurrency, spawn() a script or run functions in parallel() — real goroutines underneath, with closure safety handled for you. You get Go's concurrency without writing Go, and without the await confetti.
Hot reload isn't a build tool. Route handlers are plain scripts, checked for changes on every request. Save the file, hit refresh. There is no watcher to configure, no bundler, no restart. Dev and prod run the same binary the same way.
The datastore replaces Redis for most apps. An ACID key-value store lives in the runtime — in-memory or WAL-persisted to disk, with atomic increments, blocking waits, and real queues (push(), pop_wait()). Spawned workers coordinate through it without you setting up a single external service.
The docs are in the binary. duso doc <anything> works on a plane. duso read gives you a guided tour, duso webdoc serves the whole manual locally, and duso extract examples ./examples hands you runnable code.
Untrusted code can be sandboxed. Run a script with -no-files and it's confined to virtual filesystems (/EMBED/ read-only, /STORE/ backed by the datastore) with no real filesystem or environment access. Handy when the script was written thirty seconds ago by an LLM.
Your app can become its own binary. bundle-duso embeds your scripts, configs, and static files into a standalone executable — cross-compiled for Linux, macOS, or Windows. Deployment is scp and run.
duso script.duduso eval 'print("Hello, World!")'duso replThe AI clients are built in — no SDK to install, no wrapper library to pick:
ai = require("claude")
print(ai.prompt("What is 2+2?"))
ai = require("openai")
chat = ai.session()
while true do
prompt = input("\n\nYou: ")
if lower(prompt) == "exit" then break end
write("\n\nOpenAI: ")
busy("thinking...")
write(chat.prompt(prompt))
end
Four experts answer at once — this is parallel() doing real concurrent work, and those {{expr}} string templates are native syntax:
ai = require("claude")
prompt = input("Ask the panel: ")
busy("asking...")
experts = ["Astronomer", "Astrologer", "Biologist", "Accountant"]
responses = parallel(map(experts, function(expert)
return function()
return ai.prompt(prompt, {
system = """
You are an expert {{expert}}. Always reason and
interact from this mindset. Limit your field of
knowledge to this expertise.
""",
max_tokens = 500
})
end
end))
busy("summarizing...")
summary = ai.prompt("""
Summarize these responses:
{{join(responses, "\n\n---\n\n")}}
List 3 things they have in common.
Then list the 3 things that are the most different.
""")
print(markdown_ansi(summary))
Each handler is its own script and runs in its own goroutine. Edit one while the server is running and the next request picks it up:
// server.du
server = http_server({port = 3000})
server.route("GET", "/users/:id", "get-user.du")
server.route("POST", "/users", "create-user.du")
print("Running on :3000")
server.start()
// get-user.du
ctx = context()
user = datastore("users").get(ctx.request().params.id)
ctx.response().json(user)
// create-user.du
ctx = context()
user = ctx.request().json()
datastore("users").set(user.id, user)
ctx.response().json(user)
Ten workers, shared counters, no mutexes and no message broker:
// bees.du - Spawn workers, wait for all to finish
bees = 10
swarm = datastore("swarm")
swarm.set("done", 0)
swarm.set("buzzes", 0)
for i = 1, bees do
spawn("worker.du", {bee_id = i})
end
swarm.wait("done", bees)
print("All done! Total buzzes: " + swarm.get("buzzes"))
// worker.du - Spawned worker increments shared counters
ctx = context()
swarm = datastore("swarm")
buzzes = ceil(random() * 10)
for i = 1, buzzes do
sleep(random() * 0.5)
swarm.increment("buzzes")
end
swarm.increment("done")
The whole design is deliberately boring in the best way: one obvious way to do each thing, no metaprogramming rabbit holes, no operator overloading surprises. That predictability is also why AI assistants write good Duso on the first try — there's no trivia to trip over.
- Full web stack: routing, templates, static files, WebSockets, SSL, CORS, JWT
- SQL databases: PostgreSQL, MySQL, MariaDB, TiDB, CockroachDB — one
sql()builtin - AI integrations: Claude, OpenAI, Gemini, Groq, Ollama, Azure AI, DeepSeek
- Image processing: load, crop, scale, rotate, composite; PNG, JPEG, GIF
- Everyday tools: HTTP client, crypto, base64, UUID, date/time, Markdown rendering
- Integrated debugger: breakpoints, stack traces, concurrent-aware
- Editor support: built-in LSP server plus extensions for VS Code, JetBrains, Vim
- Starter kit:
duso init myprojectscaffolds a working project
Duso is intentionally simple and predictable. No magic. No multiple ways to do the same thing. Every pattern is consistent so AI can reason about code reliably and write better scripts faster.
Duso is a joy to use. Everything including the runtime, libs, and docs is bundled in a single 12MB binary. No package management. No version conflicts. No stack building. Duso makes coding fun again.
Dave Balmer, creator of Duso
- Website: duso.rocks
- Learning Guide: docs/learning-duso.md
- Built-in:
duso readorduso doc <topic> - Discord: Join the community
Built-in integrations for:
- AI: Claude, OpenAI, Gemini, Grok, Groq, Ollama, Azure AI, DeepSeek
- Auth: OAuth 2.0 with PKCE (
oauth), Google (oauth-google), GitHub (oauth-github) - Messaging: Discord, Slack
- Databases: CouchDB (SQL databases are handled by the built-in
sql()— no module needed) - Payments: Stripe
- Testing & Utils: Icons (Phospher), SVG graphs (svgraph), Zero Language Model (zlm)
See contrib/ for full list and docs.
Duso is open source under Apache 2.0. Contributions welcome:
- Fork github.com/duso-org/duso
- Create a branch (
git checkout -b feature/thing) - Commit changes (
git commit -am 'add thing') - Push to branch (
git push origin feature/thing) - Open a Pull Request
See CONTRIBUTING.md and COMMUNITY.md for guidelines.
- Dave Balmer: design, development, documentation, dedication
- Shannan.dev: Provides AI-driven business intelligence solutions
- Ludonode: Provides agentic development and consulting
Q: Is Duso production-ready? A: Yes.
Q: How do I deploy Duso?
A: It's one binary. scp it to a server and run it. Alternatively, containerize it in Docker or deploy to Fly.io, Railway, or Heroku.
Q: Can I bundle scripts into the binary?
A: Yes. Use bundle-duso to build a standalone executable with your scripts, configs, and static files embedded. See docs/bundling-applications.md.
Q: Can I extend Duso with Go? A: Yes. The language is designed to be extended. You can write custom builtins in Go.
Apache 2.0. See LICENSE.
