FrameOS Turns a Raspberry Pi and an E-Ink Panel into a Single-Purpose Smart Frame
Operating system for single function smart frames. Pimoroni e-ink frames Waveshare e-ink Framebuffer HDMI output Web server kiosk mode See the full list here!
At a glance
- What is it?
- FrameOS is a TypeScript operating system for single-function smart frames on Raspberry Pi, covering e-ink displays, HDMI output, and web kiosks. Its backend deploys apps over SSH, and the build system cross-compiles SD card images with Docker.
- Who is it for?
- Adopt FrameOS if you need a self-hosted way to turn a Raspberry Pi and an e-ink or HDMI display into a dedicated frame for calendars, dashboards, or signage, and you are comfortable with the AGPL-3.0 license and a Docker-based backend. Avoid it if you want a turnkey appliance with no backend dependency, or if your display is not in the supported list.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 14, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What FrameOS actually is
FrameOS is an operating system for single function smart frames. It is not a general purpose Linux distribution. It targets a Raspberry Pi connected to a display, and it is designed for two very different refresh profiles: screens that update once every 60 seconds, like e-ink, and screens that update 60 times per second, like HDMI monitors. The README lists smart home calendars, meeting room displays, thermostats, industrial dashboards, and public advertisement screens as intended use cases. The project is written in TypeScript, but the backend is a Dockerized Python app. That split matters: the device runs a lightweight runtime, while the heavy lifting happens on a separate server or local machine.
The two-part architecture: backend and frame
FrameOS separates device management from the frame itself. The backend is a Dockerized Python application that you run on a server or your computer. It deploys apps onto individual frames over SSH. The frames run independently once deployed. The README states that if the backend is offline, you miss out on log aggregation, but the frames continue working. This is a deliberate trade-off: the frame is self-sufficient, but observability depends on the backend being reachable. The backend is also where you set up scenes, either prebuilt ones or your own code. The frame itself does not need the backend to be present at runtime, which makes it suitable for always-on displays that should not fail when a central server goes down.
Getting the backend running
The quickest path is the install script for Mac or Debian/Ubuntu Linux: bash <(curl -fsSL https://frameos.net/install.sh). If you prefer Docker, the README gives a manual command. You generate a SECRET_KEY with openssl rand -base64 32, create a db directory, and run a container that maps port 8989 and mounts ./db to /app/db. The container is named frameos and set to restart always. That command is enough to start the backend. The README also notes that SD card image generation works in the default container without Docker privileges. If you want faster source builds through cross-compilation, you need to give the container access to the Docker socket, or configure a remote build server, or build on the devices themselves.
Cross-compilation and the toolchain image puzzle
Building SD card images for multiple Raspberry Pi platforms is a complex task. FrameOS handles it with prebuilt cross-toolchain containers on Docker Hub. The image name is resolved as {repo}:{base}_{version}-{platform}-{tag}, where base is the Linux distro, version is the distro version, platform is the Docker platform with slashes replaced by underscores, and tag defaults to latest. You can override this with environment variables. FRAMEOS_CROSS_TOOLCHAIN_IMAGE lets you specify a full image, FRAMEOS_CROSS_TOOLCHAIN_IMAGE_REPO changes the repository, and FRAMEOS_CROSS_TOOLCHAIN_FORCE_LOCAL_BUILD=1 forces a local rebuild. This is a practical approach for a project that must produce images for armv7, arm64, and amd64 without rebuilding the toolchain every time. But it also means you need to understand Docker image naming and the environment variables if you want to customize the build. The README gives an example for local iteration, exporting an image name that includes debian_trixie-linux_arm_v7-my-wip, which suggests you can test a work-in-progress toolchain without touching the default.
Buildroot image cache and SD card partitioning
For SD card generation, FrameOS uses Buildroot and supports a cached image that has dependency packages preinstalled and the Buildroot tarball preloaded. You control this with FRAMEOS_BUILDROOT_IMAGE and related variables. The default base image is debian:bookworm. The cache is keyed by the resolved image, so changing the configuration invalidates stale output directories automatically. The generated SD images use four partitions: p1 is FAT32 boot, p2 is ext4 root, p3 is ext4 /srv/frameos, and p4 is FAT32 /srv/assets. On first boot, the image expands to fit the SD card. On cards 4 GiB and larger, p3 grows to 2 GiB and p4 fills the rest. On smaller cards, p3 stays at 1 GiB. This partitioning is specific and sensible for a frame that needs separate storage for the OS, runtime data, and user assets. The README warns that the root partition stays at the image size, so you cannot reclaim space from the root filesystem after first boot.
Supported displays and the hardware dependency
The README says supported are all the most common e-ink displays, listing Pimoroni e-ink frames, Waveshare e-ink, framebuffer HDMI output, and web server kiosk mode. The full list is on the device hardware guide. This is the first thing to verify before adopting FrameOS. If your display is not a common Pimoroni or Waveshare model, or if you need a specific touch interface, you may be out of luck. The guide is the only source of truth. The README does not mention any simulation mode or virtual display, so you cannot test the frame experience without physical hardware. That is a real limitation for development and evaluation.
Development environment with Flox
For developers who want to contribute or modify FrameOS, the repository ships a Flox environment. Running flox activate bootstraps the core toolchains and installs dependencies for Python, pnpm, and Nim. The activation hook creates a local .venv, installs backend/requirements.txt, runs pnpm install --frozen-lockfile for the workspace, and installs Nim dependencies for frameos/ and frameos/remote/. You can also start Redis as a Flox service with flox services start redis. This is a modern way to manage a polyglot project. The use of Nim for the frame runtime is notable, though the README does not explain why Nim was chosen. The combination of TypeScript, Python, and Nim means you need to be comfortable with multiple languages if you plan to hack on the internals.
Licence and maintenance considerations
FrameOS is licensed under AGPL-3.0. That has implications for anyone who wants to offer a modified version as a service, because the AGPL requires you to make the source available to users of the network service. The README does not discuss licensing, so you should read the license text yourself. The project is actively maintained, with releases on consecutive days in August 2026, which suggests frequent updates. The release cadence is high, but that also means you need to track changes if you run your own backend. The backend can be run locally on demand, but you lose log aggregation when it is offline. That is a concrete operational cost: if you want logs, you need the backend up. The frames themselves are designed to run independently, so the maintenance burden is on the backend operator, not the frame.
Alternatives and the right fit
The obvious alternative is to build a frame from scratch using a Raspberry Pi, a display driver library, and a cron job to update the screen. That gives you full control but requires you to handle SSH deployment, display initialization, and scene management yourself. FrameOS abstracts those pieces away, but it also locks you into its backend and its build system. Another alternative is a commercial smart display dashboard, but those are closed and often cloud-dependent. FrameOS is self-hosted and AGPL, so it fits a user who wants control and is willing to run a Docker container. The right fit is a maker or a small team that has a supported display and wants to deploy multiple frames without writing device code for each one. The wrong fit is someone who wants a zero-maintenance appliance or who needs a display model that is not in the supported list.
Editorial conclusion
Adopt FrameOS if you need a self-hosted way to turn a Raspberry Pi and an e-ink or HDMI display into a dedicated frame for calendars, dashboards, or signage, and you are comfortable with the AGPL-3.0 license and a Docker-based backend. Avoid it if you want a turnkey appliance with no backend dependency, or if your display is not in the supported list. Before committing, verify that your exact screen model is supported on the device hardware guide, and test the backend on a machine that can stay online for log aggregation, since frames run independently but logs are lost when the backend is offline.
Community notes