Working FastHTML (a new Python Web Framework) dev.nix

Hi all, here is a dev.nix that works for FastHTML (and probably a Starlette app too, although haven’t tried).

Just create a blank workspace and use this dev.nix and have your app files/requirements.txt etc in the root of the project. The key is Project IDX has a predefined port that you need to use for web previews for their Python environments. You should also have your serve() in your main.py guarded by if __name__ == "__main__": as that could otherwise interfere with the IDX reloads for web preview.

This also gives an auto-logged in venv in the terminal.
I’ve also found the web preview in general (maybe just for python/fasthtml?) to be a little buggy unless you open it in a new tab (eg outside the IDE), and then the preview is fine/no issues. So I’d definitely recommend that as well.

I have no idea how to nor interest (sorry!) in creating a community template, but maybe someone who knows how to whip those up quickly can make a FastHTML template from this…

Anyways hopefully this is of use for any other FastHTML/Python peeps out there..

# To learn more about how to use Nix to configure your environment
# see: https://developers.google.com/idx/guides/devnix-reference
{ pkgs, ... }: {
  # Which nixpkgs channel to use.
  channel = "stable-24.05"; # or "unstable"

  # Add system-level packages needed for your build or runtime (NOT Python packages).
  packages = [
    pkgs.python311 # Provides the python3 interpreter and the 'venv' module
    # pkgs.rsync   # Example: Keep if needed, remove if not
  ];

  # Environment variables available system-wide in the workspace & preview
  env = {
     PYTHONUNBUFFERED = "1"; # Ensures python print() and logs appear immediately
  };

  idx = {
    # VS Code extensions: https://open-vsx.org/
    extensions = [
      "ms-python.python" # Recommended for Python development
    ];

    # Configure web previews: https://developers.google.com/idx/guides/previews
    previews = {
      # Enable previews globally
      enable = true;

      # Define individual previews
      previews = {
        web = {
          # --- Direct Uvicorn Command ---
          command = [
            ".venv/bin/uvicorn" # Execute uvicorn from the virtual env
            "main:app"          # Target 'app' object in 'main.py' (ADJUST if needed)
            "--host" "0.0.0.0"  # Bind to all interfaces
            "--port" "$PORT"     # *** Use IDX predefined Python port ***
            "--log-level" "info" # Uvicorn log level
           ];

          # --- Explicit port attribute REMOVED as linter rejects it ---
          # We rely on manager="web" to auto-detect the port from the process.

          # --- Environment Variables specifically for this Preview ---
          env = {
             # Add any other ENV VARS your specific application requires for the preview
          };

          # --- REMINDER: MODIFY YOUR FastHTML main.py CODE ---
          # You MUST remove the `serve()` call from the end of your `main.py`
          # or wrap it in `if __name__ == "__main__":` so it doesn't run when imported.

          manager = "web";
        };
        # Add other named previews here if needed
      }; # End of the 'previews' attribute set containing named previews

    }; # End of idx.previews

    # Workspace lifecycle hooks
    workspace = {
      # Runs ONCE when a workspace is first created.
      onCreate = {
        setup-venv = ''
          echo ">>> [onCreate] Creating Python virtual environment in .venv..."
          python3 -m venv .venv
          echo ">>> [onCreate] Installing initial dependencies from requirements.txt..."
          if [ -f ".venv/bin/pip" ]; then
            if [ -f "requirements.txt" ]; then
              .venv/bin/pip install -r requirements.txt
            else
              echo ">>> [onCreate] requirements.txt not found. Skipping initial install."
            fi
          else
             echo ">>> [onCreate] ERROR: .venv/bin/pip not found after creating venv."
          fi
          echo ">>> [onCreate] Initial setup complete."
        '';
      };

      # Runs EVERY time the workspace is (re)started.
      onStart = {
        install-deps = ''
          echo ">>> [onStart] Checking/installing Python dependencies..."
          if [ ! -d ".venv" ]; then
            echo ">>> [onStart] Virtual environment .venv not found. Attempting to create..."
            python3 -m venv .venv
          fi
          if [ -f ".venv/bin/pip" ]; then
            echo ">>> [onStart] Upgrading pip..."
            .venv/bin/pip install --upgrade pip
            if [ -f "requirements.txt" ]; then
              echo ">>> [onStart] Installing/updating dependencies from requirements.txt..."
              .venv/bin/pip install -r requirements.txt
            else
              echo ">>> [onStart] requirements.txt not found. Skipping dependency installation."
            fi
             echo ">>> [onStart] Dependency check complete."
             # --- Keep delay ---
             echo ">>> [onStart] Adding 5 second delay before preview starts..."
             sleep 5
          else
             echo ">>> [onStart] ERROR: .venv/bin/pip not found. Cannot install dependencies."
          fi
        '';
      };
    }; # End of idx.workspace
  }; # End of idx
} # End of file
1 Like

Thank for sharing great work