Meet Peat.

A typed functional language that compiles to JavaScript.

Write code that describes the business logic. Let the plumbing live somewhere else.

import core/http import core/http/client import core/error { Ok, Err } import core/string // Look at the inferred return type: the compiler knows // this function makes HTTP requests and can fail // (without any annotations from you) fn weather_in(city) { http.get("https://wttr.in/" ++ city ++ "?format=3") |> http.send |> http.body_text } // This function is pure: just data in, data out. fn beach_verdict(forecast) { if string.contains(forecast, "☀") { "Grab your towel!" } else if string.contains(forecast, "🌧") { "Stay in. Write some Peat instead." } else { "Check the window, honestly." } } @entrypoint fn main() { // provide an effect handler for HTTP requests with client.http_client; let result = error.try { weather_in("San Francisco") }; match result { Ok(forecast) => beach_verdict(forecast), Err(_) => "Couldn't check. Beach at your own risk.", } }

No colored functions

In most languages, calling an async function makes your function async too — and that “function color” spreads everywhere. In Peat, HTTP requests, file I/O, error handling, and state are all just function calls. The compiler tracks which effects each function uses, so you don't have to.

Type safety with minimal ceremony

Full type inference, including effects. Write your code and let the compiler figure out the types. You can add annotations anywhere, but they’re always optional.

Compiles to JavaScript or native code

Runs anywhere JS runs — Node, Deno, Bun, browsers — or compiled to native code.

The Big Idea

What if one language feature could replace async/await, try/catch, generators, dependency injection, and state management?

That feature is algebraic effects. The type of a Peat function describes the capabilities it needs — “I read files,” “I can fail” — and effect handlers, which are provided separately, decide how to handle those needs. The same mechanism models error handling, async I/O, mutable state, iteration, and interfaces.

Most languages solve each of these with a separate, special-purpose feature, and they don’t always compose easily. Peat solves them all with one concept, which composes naturally. Swap in a different handler and a function talks to a test double instead of a real database. Nest two handlers and errors inside a generator become a list of results.