### Lustre Hello World Project Setup Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-elm-devs.md This is a basic 'Hello, world' example for setting up a new project in Lustre. It shows how to start a simple Lustre application. ```gleam import lustre import lustre/element/html pub fn main() { let app = lustre.element(html.h1([], [html.text("Hello, world")])) let assert Ok(_) = lustre.start(app, "#app", Nil) Nil } ``` -------------------------------- ### Elm Hello World Project Setup Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-elm-devs.md This is a basic 'Hello, world' example for setting up a new project in Elm. It demonstrates the minimal code required to get started. ```elm module Main exposing (main) import Html main = Html.text "Hello, world" ``` -------------------------------- ### Setup New Project: Lustre Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of setting up a new Lustre project with a basic 'Hello, Joe' element. ```gleam ```gleam // main.gleam import lustre import lustre/element/html pub fn main() { let app = lustre.element(html.h1([], [html.text("Hello, Joe")])) let assert Ok(_) = lustre.start(app, "#app", Nil) Nil } ``` ``` -------------------------------- ### Setup New Project: LiveView Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of setting up a new Phoenix LiveView project with a basic 'Hello, Joe' LiveView. ```elixir ```elixir # lib/my_app_web/live/hello_live.ex defmodule MyAppWeb.HelloLive do use MyAppWeb, :live_view def render(assigns) do ~H"""

Hello, Joe

""" end def mount(_params, _session, socket) do {:ok, socket} end end ``` ``` -------------------------------- ### Lustre Server Component Setup Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Configure and start a Lustre server component. This involves defining the component's init, update, and view functions and then using `lustre.start_server_component` to initiate it. ```gleam // Server component setup let component = ServerComponent(init, update, view) lustre.start_server_component(component, req, Nil) ``` -------------------------------- ### Initiating an HTTP GET Request on Application Start Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/03-side-effects.md Demonstrates how to initiate an HTTP GET request in the `init` function using `rsvp.get` to fetch an IP address. The response is handled by `ApiReturnedIpAddress` message. ```gleam fn init(_flags) { let model = Model(loading: True, ip: None) let get_ip = rsvp.get( "https://api.ipify.org", rsvp.expect_text(ApiReturnedIpAddress) ) #(model, get_ip) } ``` -------------------------------- ### Manage State: LiveView Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of managing state in LiveView using assigns and handle_event. ```elixir ```elixir def mount(_params, _session, socket) do socket = assign(socket, :value, 1) {:ok, socket} end def handle_event("increment", _params, socket) do {:noreply, update(socket, :value, &(&1 + 1))} end def handle_event("decrement", _params, socket) do {:noreply, update(socket, :value, &(&1 - 1))} end ``` ``` -------------------------------- ### Setup React Hello World Project Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-react-devs.md Illustrates the basic setup for a barebones React project using Vite and JSX. ```jsx // src/index.js import { createRoot } from "react-dom/client"; const root = createRoot(document.getElementById("app")); root.render(

Hello, world

); ``` -------------------------------- ### LiveView Data Fetching in Mount and handle_info Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Fetch initial data in LiveView's mount callback and handle asynchronous operations or subsequent data fetches using handle_info. This example shows starting an async operation and updating the socket state. ```elixir def mount(_params, _session, socket) do if connected?(socket) do # Start async operation like Phoenix PubSub subscription or HTTP request send(self(), :fetch_data) end {:ok, assign(socket, :loading, true)} end def handle_info(:fetch_data, socket) do # Fetch data and update socket {:noreply, assign(socket, :loading, false, :data, fetch_data())} end ``` -------------------------------- ### Render HTML: LiveView Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of rendering an HTML button in LiveView using HEEx templates. ```html ```html ``` ``` -------------------------------- ### Render HTML: Lustre Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of rendering an HTML button in Lustre using function calls. ```gleam ```gleam html.button([attribute.class("primary")], [html.text("Click me")]) ``` ``` -------------------------------- ### Initialize Lustre Application Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/01-quickstart.md Sets up the main Lustre application with initialization, update, and view functions. Starts the application and attaches it to a DOM element. ```gleam import gleam/dynamic/decode import gleam/int import gleam/list import lustre import lustre/attribute import lustre/effect.{type Effect} import lustre/element.{type Element} import lustre/element/html import lustre/event import rsvp pub fn main() { let app = lustre.application(init, update, view) let assert Ok(_) = lustre.start(app, "#app", Nil) Nil } ``` -------------------------------- ### Render Text: LiveView Interpolation Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of rendering text with interpolated variables in LiveView. ```html ```html Hello <%= @name %> ``` ``` -------------------------------- ### Manage State: Lustre Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of managing state in Lustre using a Model type and an update function with a case statement. ```gleam ```gleam type Model = Int fn init(_) -> Model { 0 } type Message { Incr Decr } fn update(model: Model, message: Message) -> Model { case message { Incr -> model + 1 Decr -> model - 1 } } ``` ``` -------------------------------- ### Render Text: LiveView Simple Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of rendering plain text within a span in LiveView. ```html ```html Hello ``` ``` -------------------------------- ### Example fly.toml Configuration Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/07-full-stack-deployments.md A sample `fly.toml` file showing essential service and build configurations. Ensure `internal_port` matches your application's listening port. ```toml app = "your-app-name" [build] dockerfile = "Dockerfile" [http_service] internal_port = 8080 force_https = true auto_stop_machines = "stop" auto_start_machines = true min_machines_running = 0 processes = ["app"] [[http_service.ports]] port = 80 handlers = ["http"] [[http_service.ports]] port = 443 handlers = ["tls", "http"] ``` -------------------------------- ### Handle Events: Lustre Input Event Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of attaching an 'on_input' event handler to an input element in Lustre. ```gleam ```gleam html.input([event.on_input(UpdateInput)], []) ``` ``` -------------------------------- ### Handle Events: LiveView Input Change Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of binding a 'change' event to an input field in LiveView. ```html ```html ``` ``` -------------------------------- ### Run Lustre Dev Tools Source: https://github.com/lustre-labs/lustre/blob/main/examples/01-basics/01-hello-world/README.md Use Lustre's dev tools package to build and run the application. This command starts the development server. ```bash gleam run -m lustre/dev start ``` -------------------------------- ### Manage State with MVU in Lustre Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-react-devs.md Demonstrates state management in Lustre using the Model-View-Update (MVU) pattern with a counter example. ```gleam type Model = Int fn init(_) -> Model { 0 } type Message { Incr Decr } fn update(model: Model, message: Message) -> Model { case message { Incr -> model + 1 Decr -> model - 1 } } fn view(model: Model) -> Element(Message) { html.div([], [ html.button([event.on_click(Decr)], [html.text("-")]), html.span([], [html.text(int.to_string(model))]), html.button([event.on_click(Incr)], [html.text("+")]) ]) } ``` -------------------------------- ### Render Text: Lustre Concatenation Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of rendering concatenated text with a variable in Lustre. ```gleam ```gleam html.span([], [ html.text("Hello " <> name), ]) ``` ``` -------------------------------- ### Initialize Lustre Application Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/01-quickstart.md Starts a Lustre application using the simple API with init, update, and view functions. Ensure the target element '#app' exists in your HTML. ```gleam import gleam/int import lustre import lustre/element.{type Element} import lustre/element/html import lustre/event pub fn main() { let app = lustre.simple(init, update, view) let assert Ok(_) = lustre.start(app, "#app", Nil) Nil } ``` -------------------------------- ### Render Text: Lustre Simple Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of rendering plain text within a span in Lustre using html.text. ```gleam ```gleam html.span([], [ html.text("Hello"), ]) ``` ``` -------------------------------- ### Lustre Project Configuration with TOML Source: https://github.com/lustre-labs/lustre/blob/main/pages/announcements/2025-10-05.md Configure Lustre project settings using the `gleam.toml` file. This example shows how to specify the Bun binary, enable minification, set the output directory, configure the development server host and API proxy, and include external stylesheets and scripts. ```toml [tools.lustre.bin] # Use the system-installed `bun` binary instead of downloading one automatically. bun = "system" [tools.lustre.build] minify = true # Build the application into our server's `priv/static` directory so it can be # deployed together with the backend. outdir = "../server/priv/static" [tools.lustre.dev] host = "0.0.0.0" # Configure an API proxy to forward requests to our backend during development. # This lets us avoid CORS issues while the frontend and backend are running on # different ports. proxy = { from = "/api", to = "http://localhost:3000/api" } [tools.lustre.html] # Include Bootstrap in our project for simple styling. stylesheets = [{ href = "https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" }] scripts = [{ src = "https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" }] ``` -------------------------------- ### Run the Gleam Server Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/06-full-stack-applications.md Execute the compiled Gleam server application to start the web server and handle incoming requests. ```sh cd ../server gleam run ``` -------------------------------- ### Handle Events: Lustre Decrement Button Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of attaching an 'on_click' event handler to a button in Lustre. ```gleam ```gleam html.button([event.on_click(Decr)], [html.text("-")]) ``` ``` -------------------------------- ### Add lustre_portal to Project Source: https://github.com/lustre-labs/lustre/blob/main/pages/announcements/2025-08-08.md Install the `lustre_portal` package into your Lustre project using the Gleam package manager. ```sh gleam add lustre_portal ``` -------------------------------- ### Gleam Lustre Application Example Source: https://github.com/lustre-labs/lustre/blob/main/README.md This snippet demonstrates a basic Lustre application in Gleam, showcasing state management with increment/decrement buttons and displaying the count. It requires importing Lustre and its element modules. ```gleam import gleam/int import lustre import lustre/element.{text} import lustre/element/html.{div, button, p} import lustre/event.{on_click} pub fn main() { let app = lustre.simple(init, update, view) let assert Ok(_) = lustre.start(app, "#app", Nil) Nil } fn init(_flags) { 0 } type Message { Incr Decr } fn update(model, message) { case message { Incr -> model + 1 Decr -> model - 1 } } fn view(model) { let count = int.to_string(model) div([], [ button([on_click(Incr)], [text(" + ")]), p([], [text(count)]), button([on_click(Decr)], [text(" - ")]) ]) } ``` -------------------------------- ### Handle Events: Lustre Custom Event Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of attaching a custom 'mousemove' event handler using the general 'on' function in Lustre. ```gleam ```gleam html.div([event.on("mousemove", fn(event) { // Parse event data and return a message MouseMove(parse_coords(event)) })], []) ``` ``` -------------------------------- ### Add Server Dependencies Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/06-full-stack-applications.md Install necessary Gleam packages for the server application, including web framework, HTTP, JSON, and database libraries. ```sh cd ../server gleam add gleam_erlang gleam_http gleam_json wisp mist lustre storail ``` -------------------------------- ### GitHub Actions Workflow for Deploying to GitHub Pages Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/04-spa-deployments.md Automates the deployment of a Lustre SPA to GitHub Pages. This workflow checks out the repository, sets up Gleam, installs dependencies, builds the app, and deploys it using GitHub Actions. ```yaml name: Deploy to GitHub Pages on: push: branches: - main jobs: deploy: name: Deploy to GitHub Pages runs-on: ubuntu-latest permissions: contents: read deployments: write pages: write id-token: write steps: - name: Checkout repo uses: actions/checkout@v4 - name: Set up Gleam uses: erlef/setup-beam@v1 with: otp-version: "28.0" gleam-version: "1.12.0" rebar3-version: "3" - name: Install dependencies run: gleam deps download - name: Build app run: gleam run -m lustre/dev build --minify --outdir=dist - name: Setup Pages uses: actions/configure-pages@v5 - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: "dist" - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ``` -------------------------------- ### Add Dependencies for SSR Project Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/05-server-side-rendering.md Installs necessary dependencies including Lustre, Mist, gleam_erlang, and gleam_http for a new Gleam project. ```sh gleam new app && cd app && gleam add gleam_erlang gleam_http lustre mist ``` -------------------------------- ### Add Lustre Development Tools to Gleam Project Source: https://github.com/lustre-labs/lustre/blob/main/README.md Install the development tools for Lustre, including a development server that automatically reloads the browser on file changes. This may require inotify-tools on Linux. ```sh gleam add --dev lustre_dev_tools ``` -------------------------------- ### Lustre Stateful Component Setup Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Lustre supports stateful components using a standard MVU pattern. The `lustre.component` function initializes a component with its init, update, and view functions. ```gleam pub fn counter_component() -> Component(CounterModel, CounterMessage, CounterEvent, props) { lustre.component(counter_init, counter_update, counter_view, []) } ``` -------------------------------- ### Add Lustre to Gleam Project Source: https://github.com/lustre-labs/lustre/blob/main/README.md Install the Lustre library into your Gleam project using the Gleam package manager. ```sh gleam add lustre ``` -------------------------------- ### Prerendering a Counter Component with Declarative Shadow DOM Source: https://github.com/lustre-labs/lustre/blob/main/pages/announcements/2026-02-16.md This example shows how to use component.prerender to generate declarative shadow DOM for a component, enabling server-side rendering and hydration. ```html ``` -------------------------------- ### Add Client Dependencies and Shared Package Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/06-full-stack-applications.md Installs necessary Gleam packages for the client application and adds the shared package as a local dependency. ```sh cd ../client gleam add lustre rsvp gleam_json gleam_http plinth gleam add lustre_dev_tools --dev ``` -------------------------------- ### Controlled Input Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/hints/controlled-vs-uncontrolled-inputs.md Demonstrates a controlled input where the value is bound to the model state and changes are handled via an event. ```gleam html.input([ // The value comes from your model attribute.value(model), // Changes update your model via a message event.on_input(UserUpdatedName), // Other attributes... ]) ``` -------------------------------- ### Define Model and Initial State Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/01-quickstart.md Defines the application's data model and the initial state, including a list to hold cat data. Initializes effects to none for the starting state. ```gleam type Model { Model(total: Int, cats: List(Cat)) } type Cat { Cat(id: String, url: String) } fn init(_args) -> #(Model, Effect(Message)) { let model = Model(total: 0, cats: []) #(model, effect.none()) } ``` -------------------------------- ### Lustre Counter View Function Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/05-server-side-rendering.md This is the standard view function for the counter example, which takes an integer model and returns a Lustre Element. It's used to demonstrate how a pure view function can be leveraged for server-side rendering. ```gleam pub fn view(model: Int) -> Element(Message) { let count = int.to_string(model) html.div([], [ html.button([event.on_click(Decr)], [html.text("-")]), html.button([event.on_click(Incr)], [html.text("+")]), html.p([], [html.text("Count: " <> count)]) ]) } ``` -------------------------------- ### Create a Fly.io Application Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/07-full-stack-deployments.md Initializes a new Fly.io application in your project root. Use this to generate the basic `fly.toml` configuration. ```sh fly launch --no-deploy ``` -------------------------------- ### Create New Gleam App and Add Lustre Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/01-quickstart.md Initialize a new Gleam project and add Lustre as a dependency to begin building a web application. ```bash gleam new app && cd app && gleam add lustre ``` -------------------------------- ### Build Lustre SPA with Minification Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/04-spa-deployments.md Builds a Lustre SPA using lustre_dev_tools, minifying the output for production. Assumes the output will be in the 'priv/static' directory. ```bash gleam run -m lustre/dev build --minify ``` -------------------------------- ### Bundle Client App and Serve Static Assets Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/06-full-stack-applications.md Build the client-side JavaScript bundle and place it in the server's static directory. This command prepares the client assets for the server to serve. ```sh cd ../client gleam run -m lustre/dev build --outdir=../server/priv/static ``` -------------------------------- ### Handle Events: LiveView Decrement Button Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of binding a 'decrement' click event to a button in LiveView. ```html ```html ``` ``` -------------------------------- ### Set up Mist Server and Request Handler Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/05-server-side-rendering.md Initializes a Mist server to handle requests. It defines a handler for '/greet/:name' routes and a fallback for 404 Not Found responses. The server listens on port 3000. ```gleam pub fn main() { let empty_body = mist.Bytes(bytes_tree.new()) let not_found = response.set_body(response.new(404), empty_body) let assert Ok(_) = fn(req: Request(Connection)) -> Response(ResponseData) { case request.path_segments(req) { ["greet", name] -> greet(name) _ -> not_found } } |> mist.new |> mist.port(3000) |> mist.start process.sleep_forever() } ``` -------------------------------- ### Create Basic Lustre 'Hello, world!' Element Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/01-quickstart.md Replace the default module in src/app.gleam with this code to render 'Hello, world!' using Lustre's element API. ```gleam import lustre import lustre/element/html pub fn main() { let app = lustre.element(html.text("Hello, world!")) let assert Ok(_) = lustre.start(app, "#app", Nil) Nil } ``` -------------------------------- ### Handle Events: LiveView Custom Hook Example Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-liveview-devs.md Example of using a JavaScript hook for custom events like 'mousemove' in LiveView. ```javascript ```js let Hooks = {}; Hooks.MouseMove = { mounted() { this.el.addEventListener("mousemove", e => { this.pushEvent("mouse-move", {x: e.clientX, y: e.clientY}); }) } } ``` ``` -------------------------------- ### Manually Deploy Application to Fly.io Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/07-full-stack-deployments.md Deploys your application to Fly.io by building the Docker image, uploading it, and then deploying. Access your app at `https://your-app-name.fly.dev` after completion. ```sh fly deploy ``` -------------------------------- ### Render HTML Button in Elm Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-elm-devs.md Example of rendering an HTML button with a class attribute and an onClick event in Elm. ```elm Html.button [ Html.Attributes.class "primary" , Html.Events.onClick ButtonClicked ] [ Html.text "Click me" ] ``` -------------------------------- ### Build Minified JavaScript Bundle for Production Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/06-full-stack-applications.md Uses the Lustre build tool with the `--minify` flag to create a production-ready, minified JavaScript bundle. The `--outdir` flag specifies the output directory for the bundled file. ```sh ```sh cd ../client gleam run -m lustre/dev build --minify --outdir=../server/priv/static ``` ``` -------------------------------- ### Manage State with useState in React Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-react-devs.md Provides an example of a React counter component using the `useState` hook for state management. ```jsx import { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return (
{count}
); } ``` -------------------------------- ### Render Text in Lustre Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-elm-devs.md Example of rendering text content within a span element in Lustre, using string concatenation. ```gleam html.span([], [ html.text("Hello, " <> name), ]) ``` -------------------------------- ### Gleam Server Implementation Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/06-full-stack-applications.md The main server logic in `src/server.gleam`, setting up the database, configuring the web framework, and defining request handlers for API endpoints and static asset serving. ```gleam import gleam/dynamic/decode import gleam/erlang/process import gleam/http.{Get, Post} import gleam/json import gleam/result import lustre/attribute import lustre/element import lustre/element/html import mist import storail import wisp.{type Request, type Response} import wisp/wisp_mist import shared/groceries.{type GroceryItem} pub fn main() { wisp.configure_logger() let secret_key_base = wisp.random_string(64) // Set up our database let assert Ok(db) = setup_database() let assert Ok(priv_directory) = wisp.priv_directory("server") let static_directory = priv_directory <> "/static" let assert Ok(_) = handle_request(db, static_directory, _) |> wisp_mist.handler(secret_key_base) |> mist.new |> mist.port(3000) |> mist.start process.sleep_forever() } // REQUEST HANDLERS ------------------------------------------------------------ fn app_middleware( req: Request, static_directory: String, next: fn(Request) -> Response, ) -> Response { let req = wisp.method_override(req) use <- wisp.log_request(req) use <- wisp.rescue_crashes use req <- wisp.handle_head(req) use <- wisp.serve_static(req, under: "/static", from: static_directory) next(req) } fn handle_request( db: storail.Collection(List(GroceryItem)), static_directory: String, req: Request, ) -> Response { use req <- app_middleware(req, static_directory) case req.method, wisp.path_segments(req) { // API endpoint for saving grocery lists Post, ["api", "groceries"] -> handle_save_groceries(db, req) // Everything else gets our HTML with hydration data Get, _ -> serve_index(db) // Fallback for other methods/paths _, _ -> wisp.not_found() } } fn serve_index(db: storail.Collection(List(GroceryItem))) -> Response { let html = html.html([], [ html.head([], [ html.title([], "Grocery List"), html.script( [attribute.type_("module"), attribute.src("/static/client.js")], "", ), ]), html.body([], [html.div([attribute.id("app")], [])]), ]) html |> element.to_document_string |> wisp.html_response(200) } fn handle_save_groceries( db: storail.Collection(List(GroceryItem)), req: Request, ) -> Response { use json <- wisp.require_json(req) case decode.run(json, groceries.grocery_list_decoder()) { Ok(items) -> case save_items_to_db(db, items) { Ok(_) -> wisp.ok() Error(_) -> wisp.internal_server_error() } Error(_) -> wisp.bad_request("Request failed") } } // DATABASE -------------------------------------------------------------------- fn setup_database() -> Result(storail.Collection(List(GroceryItem)), Nil) { let config = storail.Config(storage_path: "./data") let items = storail.Collection( name: "grocery_list", to_json: groceries.grocery_list_to_json, decoder: groceries.grocery_list_decoder(), config:, ) Ok(items) } fn grocery_list_key( db: storail.Collection(List(GroceryItem)), ) -> storail.Key(List(GroceryItem)) { // In a real application, you would probably store items as individual // documents, or use a database like PostgreSQL instead. storail.key(db, "grocery_list") } fn save_items_to_db( db: storail.Collection(List(GroceryItem)), items: List(GroceryItem), ) -> Result(Nil, storail.StorailError) { storail.write(grocery_list_key(db), items) } ``` -------------------------------- ### Render Text in Elm Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-elm-devs.md Example of rendering text content within a span element in Elm, including string concatenation. ```elm Html.span [] [ Html.text <| "Hello, " ++ name ] ``` -------------------------------- ### Lustre Application Constructor Signatures Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/03-side-effects.md Compares the signatures for `lustre.simple` and `lustre.application`, highlighting the return type of `#(model, Effect(message))` for the latter. ```gleam pub fn simple( init: fn(flags) -> model, update: fn(model, message) -> model, view: fn(model) -> Element(message), ) -> App(flags, model, message) pub fn application( init: fn(flags) -> #(model, Effect(message)), update: fn(model, message) -> #(model, Effect(message)), view: fn(model) -> Element(message), ) -> App(flags, model, message) ``` -------------------------------- ### Render HTML Button in Lustre Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-elm-devs.md Example of rendering an HTML button with a class attribute and an onClick event in Lustre, using the lustre/element/html module. ```gleam html.button([attribute.class("primary"), event.on_click(ButtonClicked)], [ html.text("Click me") ]) ``` -------------------------------- ### Simulate Lustre Application Logic Source: https://github.com/lustre-labs/lustre/blob/main/pages/announcements/2025-05-18.md Use this to simulate a running Lustre application by passing your init, update, and view functions. It allows simulating events, interrupting the simulation to assert view state, and simulating messages from external systems. Effects are not simulated. ```gleam import app import app/user.{User} import lustre/dev/simulate import lustre/dev/query import lustre/element pub fn user_login_test() { let form = query.element(query.test_id("login-form")) let app = simulate.application(app.init, app.update, app.view) |> simulate.start(Nil) |> simulate.submit(on: query.element(form), fields: [ #("email", json.string("lucy@gleam.run")), #("password", json.string("strawberry")), ]) let assert Ok(_) = query.find( in: simulate.view(app), matching: query.element(matching: query.text("Loading...")), ) as "Should show loading state while logging in" let response = Ok(User(name: "Lucy", email: "lucy@gleam.run", role: "mascot")) app |> simulate.message(ApiReturnedSession(response)) |> simulate.view |> element.to_readable_string |> birdie.snap("The dashboard after logging in") } ``` -------------------------------- ### Initial Message Definition Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/02-state-management.md An example of a muddled message definition before applying the Subject Verb Object pattern. This can become problematic as applications grow. ```gleam type Message { SetPassword(String) ResetPassword PasswordReset(Result(Nil, String)) } ``` -------------------------------- ### Get PORT Environment Variable Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/07-full-stack-deployments.md Retrieves the PORT environment variable, attempting to parse it as an integer. It defaults to 8080 if the variable is not set or cannot be parsed. ```Gleam // In server.gleam fn get_port() -> Int { case envoy.get("PORT") { Ok(port) -> { case int.parse(port) { Ok(port_number) -> port_number Error(_) -> 8080 // Default if PORT cannot be parsed as an int } } Error(_) -> 3000 // Default if PORT is not set (e.g. during `gleam run`) } } ``` -------------------------------- ### Get HOST Environment Variable Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/07-full-stack-deployments.md Retrieves the HOST environment variable, defaulting to 'localhost' if not set. This is used for server configuration in production environments. ```Gleam // In server.gleam fn get_host() -> String { case envoy.get("HOST") { Ok(host) -> host Error(_) -> "localhost" // Default if HOST is not set } } ``` -------------------------------- ### Create Monorepo and Gleam Projects Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/06-full-stack-applications.md Initializes a new monorepo for a full stack application and creates separate Gleam projects for the client, server, and shared code. ```sh mkdir lustre-fullstack-guide \ && cd lustre-fullstack-guide \ && gleam new client \ && gleam new server \ && gleam new shared ``` -------------------------------- ### Optimize Render Performance with element.memo Source: https://github.com/lustre-labs/lustre/blob/main/pages/announcements/2026-01-10.md Use element.memo to hint to the runtime when rendering can be skipped. It requires a list of dependencies constructed with element.ref and a view function that takes no arguments. Dependencies are checked for reference equality. ```diff fn view_entry(entry: Entry) { + use <- element.memo([element.ref(entry)]) let Entry(description:, id:, completed:, editing:, ..) = entry html.li( [attribute.classes([#("completed", completed), #("editing", editing)])], [...], ) } ``` -------------------------------- ### Pure Function Example in Gleam Source: https://github.com/lustre-labs/lustre/blob/main/pages/hints/pure-functions.md A simple Gleam function demonstrating purity. It takes an input and returns an output solely based on that input, without external side effects. ```gleam fn f(x) { 3 * x } ``` -------------------------------- ### Import Server-Side Rendering Modules Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/05-server-side-rendering.md Imports modules required for handling HTTP requests and rendering HTML with Lustre on the server. Does not import from the main 'lustre' module as no runtime is needed. ```gleam import gleam/bytes_tree import gleam/erlang/process import gleam/http/request.{type Request} import gleam/http/response.{type Response} import lustre/element import lustre/element/html.{html} import mist.{type Connection, type ResponseData} ``` -------------------------------- ### Declarative Event Handling with `gleam/dynamic/decode` Source: https://github.com/lustre-labs/lustre/blob/main/pages/announcements/2025-04-19.md Migrate imperative event handlers to a declarative approach using `gleam/dynamic/decode`. This example shows how to extract and decode event data within the handler definition. ```gleam // Before: event.on("mousemove", fn(event) { use x <- result.try(dynamic.field("offsetX", dynamic.int)(event)) use y <- result.try(dynamic.field("offsetY", dynamic.int)(event)) Ok(handle_mousemove(x, y)) }) // After: event.on("mousemove", { use x <- decode.field("offsetX", decode.int) use y <- decode.field("offsetY", decode.int) decode.success(handle_mousemove(x, y)) }) ``` -------------------------------- ### Dockerfile for Lustre Full-Stack Application Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/07-full-stack-deployments.md Defines the build and runtime stages for a Lustre full-stack application using a multi-stage Docker build. It compiles both client and server code and sets up the runtime environment. ```Dockerfile ARG GLEAM_VERSION=v1.12.0 # Build stage - compile the application FROM ghcr.io/gleam-lang/gleam:${GLEAM_VERSION}-erlang-alpine AS builder # Add project code COPY ./shared /build/shared COPY ./client /build/client COPY ./server /build/server # Install dependencies for all projects RUN cd /build/shared && gleam deps download RUN cd /build/client && gleam deps download RUN cd /build/server && gleam deps download # Compile the client code and output to server's static directory RUN cd /build/client \ # Add this line if your project doesn't already have a dev dependency # on `lustre_dev_tools` - otherwise, you can omit it && gleam add --dev lustre_dev_tools \ && gleam run -m lustre/dev build --minify --outdir=../server/priv/static # Compile the server code RUN cd /build/server \ && gleam export erlang-shipment # Runtime stage - slim image with only what's needed to run FROM ghcr.io/gleam-lang/gleam:${GLEAM_VERSION}-erlang-alpine # Copy the compiled server code from the builder stage COPY --from=builder /build/server/build/erlang-shipment /app # Set up the entrypoint WORKDIR /app RUN echo -e '#!/bin/sh\nexec ./entrypoint.sh "$@"' > ./start.sh \ && chmod +x ./start.sh # Set environment variables ENV HOST=0.0.0.0 ENV PORT=8080 # Expose the port the server will run on EXPOSE $PORT # Run the server CMD ["./start.sh", "run"] ``` -------------------------------- ### Define Counter Model and Init Function Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/01-quickstart.md Defines the application's state as an integer and initializes it to 0. The init function accepts optional arguments which are ignored in this simple case. ```gleam type Model = Int fn init(_args) -> Model { 0 } ``` -------------------------------- ### Configure Server Dependencies in gleam.toml Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/06-full-stack-applications.md Add the shared Gleam package as a dependency in the server's `gleam.toml` file to enable code sharing between client and server. ```toml [dependencies] shared = { path = "../shared" } ``` -------------------------------- ### Keying list elements with `element.keyed` Source: https://github.com/lustre-labs/lustre/blob/main/pages/hints/rendering-lists.md Demonstrates how to use `element.keyed` to provide stable keys for list items, ensuring correct DOM updates and preventing visual issues. ```gleam keyed.div([], list.map(model.cats, fn(cat) { #(cat.id, html.img([attribute.src(cat.url)])) })) ``` -------------------------------- ### Greet Function for Server-Side Rendering Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/05-server-side-rendering.md Generates an HTML response with a personalized greeting. It uses Lustre's element functions to construct the HTML and 'element.to_document_string' to render it. ```gleam fn greet(name: String) -> Response(ResponseData) { let res = response.new(200) let html = html([], [ html.head([], [html.title([], "Greetings!")]), html.body([], [ html.h1([], [html.text("Hey there, " <> name <> "!")]) ]) ]) response.set_body(res, html |> element.to_document_string |> bytes_tree.from_string |> mist.Bytes ) } ``` -------------------------------- ### Configure Client as JavaScript Target Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/06-full-stack-applications.md Sets the target for the client project to 'javascript' and adds the shared package as a local dependency in its gleam.toml. ```toml [dependencies] shared = { path = "../shared" } name = "client" version = "1.0.0" target = "javascript" ``` -------------------------------- ### Client-Side Hydration Logic Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/05-server-side-rendering.md This client-side Gleam code shows how to read the initial model from a JSON script tag, decode it, and start a Lustre application. It includes fallback logic for cases where JSON decoding might fail. ```gleam import gleam/dynamic import gleam/json import gleam/result import lustre import plinth/browser/document import plinth/browser/element pub fn main() { let json = document.query_selector("#model") |> result.map(element.inner_text) let flags = case json.parse(json, decode.int) { Ok(count) -> count Error(_) -> 0 } let app = lustre.application(init, update, view) let assert Ok(_) = lustre.start(app, "#app", flags) Nil } ``` -------------------------------- ### Render Text in Lustre Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-react-devs.md Shows how to render text and concatenated strings using `html.text` and the string concatenation operator in Lustre. ```gleam html.div([], [html.text("Hello")]) html.div([], [html.text("Hello " <> name)]) ``` -------------------------------- ### Add Envoy Dependency to Server Source: https://github.com/lustre-labs/lustre/blob/main/pages/guide/07-full-stack-deployments.md Adds the 'envoy' Hex package to your server project for managing environment variables. Run this command in the 'server' directory. ```shell cd server gleam add envoy ``` -------------------------------- ### Create Lustre View Functions Source: https://github.com/lustre-labs/lustre/blob/main/pages/reference/for-react-devs.md Create view functions that return elements. Use messages for event handling and pass data via function arguments. ```gleam fn button(label: String, on_click: message) -> Element(message) { html.button([event.on_click(on_click)], [html.text(label)]) } fn view(_model: Model) -> Element(Message) { html.div([], [ button("Click me", ButtonClicked) ]) } ```