Skip to content

Make Nix and NixOS version simpler #352

@miklevin

Description

@miklevin

Hi @dullage,

First off, thank you for Flatnotes! The "folder of markdown files" philosophy is fantastic and exactly what many of us in the self-hosted / "Local-First" community are looking for.

I am opening this issue to share some friction points I encountered while packaging Flatnotes for NixOS. My goal is to suggest architectural tweaks that would make Flatnotes easier to package for distributions that prioritize immutable, reproducible builds (like NixOS, Guix, and others), which could eventually help it get into official package repositories (e.g., nixpkgs).

Currently, creating a native derivation is difficult because the project structure assumes a mutable, imperative install process (like Docker) where the application can modify itself at runtime.

The Pain Points

Here are the specific technical hurdles encountered when trying to build Flatnotes from source in a restricted, sandboxed environment:

1. Runtime Self-Modification (The Read-Only File System Issue)
This was the biggest blocker. The application currently attempts to rewrite its own source code at startup.

  • Issue: main.py calls replace_base_href (in helpers.py), which attempts to open index.html in write mode ("w") to inject the path_prefix.
  • Impact: On secure systems or container setups where the application code is immutable (e.g., /nix/store/..., or a read-only Docker container), this causes the service to crash immediately with OSError: [Errno 30] Read-only file system.
  • Suggestion: Inject configuration variables (like path_prefix) into the frontend at runtime using a non-destructive method—for example, injecting it into the HTML response in memory, or having the frontend fetch a config.json endpoint—rather than rewriting the static asset on disk.

2. Hardcoded Relative Paths
The Python server seems to assume the client/dist folder is relative to the process's Current Working Directory (os.getcwd()).

  • Issue: When running as a system service, the Working Directory is often the data directory (e.g., /var/lib/flatnotes) to ensure saved notes go to the right place. However, the application code lives elsewhere (e.g., /usr/share/flatnotes or /nix/store/...). This triggers a FileNotFoundError because the app looks for client/dist inside /var/lib/flatnotes.
  • Suggestion: Resolve static asset paths relative to the __file__ location of the running script, rather than the CWD.
  • Example: BASE_DIR = Path(__file__).resolve().parent

3. The "Monorepo" Structure vs. Build Isolation
The project mixes the frontend (Node.js/Vite) and backend (Python/FastAPI) in a way that is hard to build separately.

  • Issue: The frontend source is in client/, but package.json and vite.config.js are in the root. This forces the builder to download the entire repo (including python files) just to build the frontend assets, complicating dependency hashing and caching.
  • Suggestion: Moving frontend concerns (including package.json) strictly inside the client/ directory would allow package managers to build the frontend as a distinct, isolated artifact before handing it to Python.

4. Binary Dependencies (sass-embedded)
The frontend build pulls in sass-embedded, which downloads a pre-compiled dart binary during npm install.

  • Issue: On source-based distros, pre-compiled binaries often fail because they expect standard FHS paths (like /lib64/ld-linux...) which may not exist.
  • Suggestion: This is largely an upstream issue with sass, but providing a flag or documentation to use a pure-JS alternative for Sass compilation would improve portability.

Why this matters

Fixing these issues wouldn't just help NixOS users; it would make Flatnotes more robust and compliant with "Twelve-Factor App" principles. It would allow the application to run:

  1. From a strictly read-only container/filesystem (significant security benefit).
  2. With standard Linux directory structures (FHS compliant).
  3. Without needing Docker, reducing overhead for low-power devices.

I managed to get it working by applying several sed patches during the build to disable the file writing and fix paths, but having upstream support would be amazing.

Thanks again for the great tool!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions