Skip to content

Nubo ☁️

Write a file, run it, or serve it as a web app. Nubo is built for simple, interactive web development.

Nubo starts simple. Create a .nubo file and run it directly.

hello.nubo
let name = "Nubo"
println("Hello, " + name)
Terminal window
nubo hello.nubo
Hello, Nubo

No server. No framework. No project structure required.

A .nubo file can also be an HTTP route.

index.nubo
import request from "@server/request"
import response from "@server/response"
let name = request.query("name")
if isNil(name) {
name = "World"
}
response.write(<h1>Hello, { name }</h1>)
Terminal window
nubo serve .

Open:

http://localhost:3000/?name=Nubo

Nubo gives you direct access to the request and response, so small web apps stay small.

Fast to start

Run nubo file.nubo for scripts, or nubo serve . for a web app. The first useful program can be one file.

Web features built in

Routes, request data, JSON responses, cookies, uploads, static files, and custom error pages are part of the Nubo server workflow.

Typed, but not noisy

Let Nubo infer simple values, then add types for functions, lists, dictionaries, structs, interfaces, and function values when structure matters.

HTML is part of the language

Return html values, build components, pass children, bind attributes, and compose pages without switching languages.

Serve a folder and Nubo maps files to routes.

app/
index.nubo
users/
[id].nubo
error.nubo

Dynamic route params are available through @server/request.

app/users/[id].nubo
import request from "@server/request"
import response from "@server/response"
let id = request.param("id")
response.json({
"id": id
})
GET /users/42
{
"id": "42"
}

Read JSON from the request and return JSON from the response.

api/echo.nubo
import request from "@server/request"
import response from "@server/response"
if !request.is("POST") {
response.status(405)
response.json({
"error": "method not allowed"
})
return
}
let data = request.json()
response.json({
"ok": true,
"received": data
})

That is enough for small APIs, internal tools, prototypes, dashboards, and webhooks.

Nubo can infer types:

inferred.nubo
let title = "Dashboard"
let count = 5
let enabled = true

Add annotations where they help:

typed.nubo
let names: []string = ["Nubo", "Cloud"]
let scores: dict[string, int] = {
"nubo": 100
}

Create your own types:

user.nubo
struct User {
name: string
roles: []string
}
fn hasRole(user: User, role: string) bool {
return user.roles.includes(role)
}

Function implementations use the return type after the parameter list:

functions.nubo
fn greet(name: string) string {
return "Hello, " + name
}

Use -> only for function value types:

function-values.nubo
let formatter: fn(string) -> string

Use @std/component to build reusable HTML components.

button.nubo
import { Context } from "@std/component"
fn Button(ctx: Context) html {
return <button class="btn">
{ ctx.children.join(" ") }
</button>
}

Then compose it like HTML:

page.nubo
let page = <main>
<h1>Nubo App</h1>
<Button>Save changes</Button>
</main>
println(page)

Normal interpolation escapes content.

safe-html.nubo
let name = <script>alert(1)</script>
let safe = <p>{ name }</p>

Use !{ ... } only when you intentionally want raw HTML.

raw-html.nubo
let html = <strong>Nubo</strong>
let raw = <p>!{ html }</p>

Nubo includes standard libraries for common app work.

stdlib.nubo
import http from "@std/http"
import json from "@std/json"
import sql from "@std/sql"
import hash from "@std/hash"
import io from "@std/io"
import time from "@std/time"

Hash a password:

password.nubo
import hash from "@std/hash"
let password = "secret"
let hashed = hash.bcrypt(password)
if hash.bcrypt.compare(password, hashed) {
println("password ok")
}

Make an HTTP request:

http.nubo
import http from "@std/http"
let res = http.base.request("GET", "https://example.com")
println(res.status)
println(res.body())

Run a process:

process.nubo
import process from "@std/process"
let result = process.run("git", ["--version"])
println(result.stdout)

Nubo can use packages from GitHub.

Terminal window
nubo get github.com/nubolang/color
colors.nubo
import color from "github.com/nubolang/color"
println(color.green("success"))
println(color.yellow("warning"))
println(color.red("error"))

Small web apps

Build pages, forms, dashboards, and APIs without pulling in a large framework.

Internal tools

Connect HTTP, SQL, JSON, IO, processes, hashing, SSH, Telnet, or serial communication in a small codebase.

Prototypes

Try ideas quickly with file-based routes, simple types, and HTML returned directly from Nubo.

Scripts that can grow

Start with nubo file.nubo, then move the same code toward a server route or package when needed.

Terminal window
go install github.com/nubolang/nubo/cmd/nubo@latest
nubo init
nubo hello.nubo
nubo serve .