Open-Source Wikis

/

Zed

/

Systems

/

GPUI

zed-industries/zed

GPUI

Active contributors: mikayla-maki, Anthony-Eid, cameron1024, probably-neb

Purpose

GPUI is Zed's homegrown UI framework. It provides windowing, GPU-accelerated rendering, input handling, layout (flexbox-style), an entity/state model, and an async runtime built around a single foreground thread. It is the substrate every other UI crate sits on.

Directory layout

crates/
├── gpui/                  # The framework. ~62k LOC
│   ├── docs/              # Internal docs
│   ├── examples/          # Self-contained example apps
│   ├── resources/         # Shaders, fonts, default assets
│   └── src/               # Library code
├── gpui_platform/         # Cross-platform window/event abstraction
├── gpui_wgpu/             # WGPU-based renderer (cross-platform)
├── gpui_macos/            # macOS native window glue
├── gpui_linux/            # X11 / Wayland window glue
├── gpui_windows/          # Win32 window glue
├── gpui_web/              # Web target (experimental)
├── gpui_macros/           # Procedural macros (e.g. #[derive(IntoElement)])
├── gpui_shared_string/    # The SharedString type (`Arc<str>` or `&'static str`)
├── gpui_tokio/            # Tokio bridge (for crates that need a Tokio runtime)
├── gpui_util/             # Misc helpers (collections, channels)

Key abstractions

Type Purpose
Application The OS-level app singleton. Created in main
App Root context. Globals, entity registry, system services
Window OS-level window. Focus, dispatch, draw
Entity<T> Reference-counted handle to state
WeakEntity<T> Weak handle (returns Result on access)
Context<T> Mutating context for an Entity<T>. Derefs to App
AsyncApp, AsyncWindowContext Contexts that survive .await
Element / IntoElement The render-tree primitives
Render / RenderOnce Traits implemented by views and stateless components
Task<R> A future returned by cx.spawn or cx.background_spawn
SharedString Arc<str> or &'static str — used everywhere strings are displayed
actions! / Action Macro and derive for typed actions
EventEmitter<E> Marker trait for entities that emit events
Subscription RAII handle returned by observe/subscribe
FocusHandle Routes keyboard focus + actions

How it works

The single-thread invariant

All entity updates, observations, events, and rendering happen on one foreground thread. The type system enforces this: App and Context<T> are not Send. To do work elsewhere you cross into a Task via cx.spawn (foreground async) or cx.background_spawn (threadpool).

graph LR
    main[Foreground thread] -->|cx.spawn| async[AsyncApp / future]
    main -->|cx.background_spawn| bg[Background thread pool]
    bg -->|Task::ready / await| async
    async -->|update entity| main

Entity update pattern

let counter = cx.new(|_cx| Counter { value: 0 });

counter.update(cx, |this, cx| {
    this.value += 1;
    cx.notify();        // re-render any view of this entity
    cx.emit(Bumped);    // notify subscribers
});

Inside the closure you must use the inner cx — capturing the outer one breaks borrow rules and the inner one is what's actually live.

Render trait

struct Greeting(SharedString);

impl Render for Greeting {
    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
        div().text_lg().child(self.0.clone())
    }
}

For stateless components, prefer RenderOnce plus #[derive(IntoElement)]. The style methods are Tailwind-flavored (.px_2(), .bg(color), .rounded_md()).

Subscriptions and observers

let _sub = cx.observe(&other, |this, other, cx| {
    /* called whenever other.notify() fires */
});

let _sub = cx.subscribe(&other, |this, other, event: &SomeEvent, cx| {
    /* called when other emits SomeEvent */
});

Subscription handles deregister on drop. Typically held in a _subscriptions: Vec<Subscription> field.

Actions

actions!(my_panel, [Reload, ClearAll]);

div().on_action(cx.listener(|this, _: &Reload, window, cx| {
    this.reload(cx);
}))

For data-bearing actions, use #[derive(Action)]. Doc comments become user-visible help.

Tasks

let task = cx.spawn(async move |cx| {
    let data = fetch().await?;
    cx.update(|cx| {
        // update entities, render, etc.
    })
});
task.detach_and_log_err(cx);   // OR await it OR store it

A dropped Task is cancelled. Unless you intend cancellation, detach, await, or store it.

Integration points

  • Used by: every crate that touches the UI. The editor, agent_ui, workspace, and ui crates are the heaviest users.
  • Backed by: gpui_wgpu for rendering, gpui_macos/linux/windows for windowing.
  • Bridges: gpui_tokio lets Tokio-only libraries run alongside the GPUI executor.

Entry points for modification

  • New element type — implement Element (low-level) or RenderOnce (high-level).
  • New global — register in the GPUI app via cx.set_global(value).
  • New input gesture — extend Window event handling in crates/gpui/src/window.rs.
  • Per-platform windowing — gpui_{macos,linux,windows}/src.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

GPUI – Zed wiki | Factory