# Server state and reusable TSX components

> Documentation for Redweb 0.15.0. Install that exact version when following these examples.

Ordinary TSX expressions read server-owned state and update automatically after an action; no repeated binding names or browser component runtime.

Use the [complete realtime recipe](/docs/reference/0.15.0/recipes/realtime.md) for setup, files, and tests.

```tsx
import { action, defineApp, page, state } from 'redweb';

@page('/', { css: 'app.css', shared: true })
export class CounterPage {
    @state() count = 0;

    @action()
    increment() { this.count += 1; }

    render() {
        return (
            <main class="home">
                <h1>A counter owned by the server</h1>
                <p>Open this page in two tabs. Either button updates both.</p>
                <button rw-click="increment">
                    Count {this.count}
                </button>
            </main>
        );
    }
}

export const app = defineApp({ pages: [CounterPage], port: Number(process.env.PORT ?? 8181), templateRoot: __dirname });

if (require.main === module) void app.run().catch(error => { console.error(error); process.exitCode = 1; });
```

## Notes and boundaries

- The first response is complete server-rendered HTML.
- Function components handle stateless snippets; decorated classes own state and actions.
- There is no React dependency, virtual DOM, or hydration pass.
