A web framework for the BEAM
Build fault-tolerant, distributed web applications in Erlang, Elixir, or LFE.
Nova is the web framework for the BEAM. Whether you write Erlang, Elixir, or LFE, Nova gives you the productivity of a modern web framework on the runtime you already trust:
- Routing, controllers, and views — familiar MVC patterns that map naturally to Erlang modules
- Plugin pipeline — composable middleware for auth, CORS, logging, and custom concerns
- WebSockets and Pub/Sub — real-time features backed by OTP's
pgmodule, distributed out of the box - Session management — ETS-backed by default, pluggable for custom backends
- Template rendering — ErlyDTL (Django Template Language) with hot reload
- OTP-native — your web app is a proper OTP application with supervision trees, hot code upgrades, and releases
Nova runs on Cowboy and supports Erlang, Elixir, and LFE.
Install the rebar3 plugin:
# One-line install
sh -c "$(curl -fsSL https://raw.githubusercontent.com/novaframework/rebar3_nova/master/install.sh)"
# Or add to ~/.config/rebar3/rebar.config
{project_plugins, [rebar3_nova]}.Create and run your app:
rebar3 new nova my_app
cd my_app
rebar3 nova serveOpen localhost:8080 — you're running Nova.
-module(my_app_main_controller).
-export([index/1, create/1]).
index(#{method := <<"GET">>} = _Req) ->
{json, #{message => <<"Hello from Nova!">>}}.
create(#{method := <<"POST">>, json := Body} = _Req) ->
%% Validate, persist, respond
{json, #{status => <<"created">>, data => Body}}.Route it:
routes(_Environment) ->
[#{prefix => "/api",
security => false,
routes => [
{"/", {my_app_main_controller, index}},
{"/items", {my_app_main_controller, create}}
]}].| Feature | Details |
|---|---|
| Routing | Path parameters, prefixes, per-route security, environment-based routing |
| Controllers | Return {json, Map}, {ok, Variables}, {status, Code}, {redirect, Path}, {sendfile, ...} |
| Plugins | Pre/post request hooks — built-in CORS, CSRF, correlation ID, or write your own |
| WebSockets | Full WebSocket support via nova_websocket behaviour |
| Pub/Sub | Distributed messaging via nova_pubsub — channels, topics, broadcast |
| Sessions | ETS-backed sessions with pluggable backends |
| Templates | ErlyDTL (Django-style) with hot reload via rebar3 nova serve |
| Security | Per-route security functions for authentication and authorization |
| Static files | Built-in file controller with range request support |
| Observability | OpenTelemetry integration for tracing and metrics |
| Database | Kura — an Ecto-inspired database layer for Erlang |
Request → Cowboy → Nova Router → Plugins (pre) → Security → Controller → Plugins (post) → Response
| Package | Description |
|---|---|
| nova | Core framework |
| rebar3_nova | Project scaffolding and generators |
| nova_test | Testing utilities and request builder |
| kura | Database layer — schemas, migrations, changesets, queries |
| rebar3_kura | Migration generator for Kura |
| opentelemetry_nova | Automatic OpenTelemetry instrumentation |
- The Nova Book — step-by-step tutorial building a complete blog platform
- API Reference — module documentation on HexDocs
- Quick Start Guide — get up and running in 5 minutes
- Erlang/OTP 23+
- Rebar3
- Erlang Slack —
#erlangerchannel - Nova Forum — questions and discussion
- Issue Tracker — bugs and feature requests
Contributions are welcome! Check CODE_OF_CONDUCT.md and look for issues labeled good first issue.
