---
title: Installation
description: Install ilha and start from official templates for Vite SPA and Oxide SPA.
---

Install ilha with your package manager. For a new project, start from a template so routing and mounting are already wired.

## Install

```package-install
npm i ilha effect
```

`effect` is a peer dependency. Ilha atoms and streams sit on Effect.

## Templates

| Template | Command | Sandbox |
| --- | --- | --- |
| [Vite SPA](https://github.com/ilhajs/ilha/tree/main/templates/vite-spa) | `npx giget@latest gh:ilhajs/ilha/templates/vite-spa` | [Open](https://stackblitz.com/github/ilhajs/ilha/tree/main/templates/vite-spa) |
| [Oxide SPA](https://github.com/ilhajs/ilha/tree/main/templates/oxide-spa) | `npx giget@latest gh:ilhajs/ilha/templates/oxide-spa` | [Open](https://stackblitz.com/github/ilhajs/ilha/tree/main/templates/oxide-spa) |

Vite SPA is a client app with file routes. Oxide SPA adds server pages, frames, and `action` from `oxidejs`.

## Requirements

- ESM modules.
- TypeScript for the best editor support.
- A browser for `mount()`.
- JSON-serializable atom snapshots when you hydrate.

## Import

```tsx twoslash
import { atom, mount, renderToString } from "ilha";
```

Named exports you will use most:

```tsx twoslash
import { atom, when, mount, renderToString, h, Fragment } from "ilha";
```

Custom elements come from `ilha/define`:

```tsx twoslash
import { define } from "ilha/define";
```

## Minimal example

```tsx twoslash
import { atom } from "ilha";

const Greeting = () => <p>Hello, ilha!</p>;

const Counter = () => {
  const count = atom(0);
  return (
    <button type="button" onclick={() => count.update((n) => n + 1)}>
      Count: {count}
    </button>
  );
};
```

## Server-side rendering

```tsx twoslash
import { atom, renderToString } from "ilha";

const Counter = () => {
  const count = atom(0);
  return (
    <button type="button" onclick={() => count.update((n) => n + 1)}>
      Count: {count}
    </button>
  );
};

const html = await renderToString(Counter);
```

`renderToString` waits until in-flight work is idle, then serializes. Pass `{ timeout: ms }` to cut off early.

## Client-side mounting

```tsx twoslash
import { mount } from "ilha";

const Counter = () => <p>Count</p>;

const root = document.getElementById("app");
if (root) {
  const unmount = mount(root, Counter);
}
```

The returned function stops listeners and in-flight work. Call it when you remove the host.
