RatMinimal web framework

Rat Programming Language

Build full-stack web apps in one language. Frontend, backend, and database all live in Rat. Ship a single binary with no runtime to install.

DownloadRead the docs

Create your first app

curl -fsSL https://rat-lang.com/install.sh | sh
rat new my-app
cd my-app
rat start
[rat] compiled 14 files in 1.8ms
[rat] ready at http://127.0.0.1:8000 (mode: dev, hot-reload: on)
powershell -c "irm https://rat-lang.com/install.ps1 | iex"
rat new my-app
cd my-app
rat start
[rat] compiled 14 files in 1.8ms
[rat] ready at http://127.0.0.1:8000 (mode: dev, hot-reload: on)

RAT Request Flow

01 · a request lands in the Go binary with a fresh CSP nonce, session, and security headers

Dynamic Styling in RAT

> []
    brown_rat: {  }
    black_rat: {  }
    gap:       1rem

> [.card]
    color: [black_rat]
    padding: [gap] [gap * 2]
    border-left: 3px solid [brown_rat]

> [.card:hover]
    border-color: [brown_rat]

> [@media (max-width: 600px)]
    [.card]
        padding: [gap * 0.5]

Call any function from any language

def analyze(text):
    words = text.split()
    stats = {'words': len(words)}
    stats['longest'] = max(words, key=len)
    return stats
> server
report: text.analyze('the quick brown fox')

> page
<p> [report.words] words, longest [report.longest]
export function analyze(text) { const words = text.split(/\s+/) const longest = words.reduce((a, b) => b.length > a.length ? b : a) return { words: words.length, longest } }
> server
report: text.analyze('the quick brown fox')

> page
<p> [report.words] words, longest [report.longest]
def analyze(text)
  words = text.split
  { 'words' => words.length, 'longest' => words.max_by(&:length) }
end
> server
report: text.analyze('the quick brown fox')

> page
<p> [report.words] words, longest [report.longest]
analyze <- function(text) { words <- strsplit(text, "\\s+")[[1]] list(words = length(words), longest = words[which.max(nchar(words))]) }
> server
report: text.analyze('the quick brown fox')

> page
<p> [report.words] words, longest [report.longest]
func Analyze(text string) map[string]any { words := strings.Fields(text) longest := "" for _, w := range words { if len(w) > len(longest) { longest = w } } return map[string]any{"words": len(words), "longest": longest} }
> server
report: text.analyze('the quick brown fox')

> page
<p> [report.words] words, longest [report.longest]

Import any javascript library

import Chart from '/vendor/chart.mjs'

export function bar(id, labels, data) { const el = document.getElementById(id) return new Chart(el, { type: 'bar', data: { labels, datasets: [{ data }] } }) }
> page
<canvas id['sales']>
<button on_click[draw()]> draw

> draw[] [page]
    chart.bar('sales', ['Q1', 'Q2', 'Q3'], [12, 19, 7])
import * as THREE from '/vendor/three.mjs'

export function cube(id) { const canvas = document.getElementById(id) const renderer = new THREE.WebGLRenderer({ canvas }) const scene = new THREE.Scene() scene.add(new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshNormalMaterial())) renderer.render(scene, new THREE.PerspectiveCamera()) }
> page
<canvas id['stage']>

> mounted[] [page]
    scene.cube('stage')
rat add tailwindcss
# drops public/vendor/tailwind.css
> page
<div class['flex gap-4 p-6 rounded-xl bg-slate-100']>
    <h1 class['text-2xl font-bold']> Tailwind, beside Rat tokens

Default Secure Page Manifests

Additional Support

Hot Reload

pageshot reloadcold loadfull build
100.5 ms2.0 ms8.7 ms
1002.6 ms9.4 ms75 ms
100061 ms195 ms1.3 s