Getting Started

FluidKit bridges Python and SvelteKit into a unified fullstack framework. Write backend functions in Python — FluidKit registers them as FastAPI endpoints and generates SvelteKit remote functions with full type safety.

Installation

No system Node.js required — FluidKit bundles it automatically.

pip install fluidkit

Create a project

fluidkit init my-app
cd my-app

This scaffolds a SvelteKit project with FluidKit wired in and a working demo app:

Project structure
my-app/
├── src/
│   ├── routes/
│   │   ├── +layout.svelte
│   │   └── +page.svelte
│   ├── lib/
│   │   ├── demo.py              # your backend logic
│   │   └── demo.remote.ts       # generated — don't edit
│   └── app.py                   # FastAPI entry point
├── fluidkit.config.json
├── svelte.config.js
└── package.json

Run it

fluidkit dev

This starts both the FastAPI backend and Vite dev server together with hot module reloading. Open the app and you'll see a working posts demo — try adding posts and liking them.

How the demo works

The scaffolded demo.py contains three decorated functions:

src/lib/demo.py python
from fluidkit import query, command, form

db = {
    "posts": [
        {"id": 1, "title": "Hello World", "content": "First post.", "likes": 10},
    ]
}

@query
async def get_posts():
    return db["posts"]

@command
async def like_post(post_id: int):
    for post in db["posts"]:
        if post["id"] == post_id:
            post["likes"] += 1
            await get_posts().refresh()
            return True
    return None

@form
async def add_post(title: str, content: str):
    new_post = {
        "id": len(db["posts"]) + 1,
        "title": title,
        "content": content,
        "likes": 0,
    }
    db["posts"].append(new_post)
    await get_posts().refresh()

The route imports and uses them directly:

src/routes/+page.svelte svelte
<script>
  import { get_posts, like_post, add_post } from '$lib/demo.remote';
</script>

<form {...add_post}>
  <input {...add_post.fields.title.as('text')} placeholder="Title" />
  <input {...add_post.fields.content.as('text')} placeholder="Content" />
  <button>Add Post</button>
</form>

{#each await get_posts() as post}
  <div>
    <h2>{post.title}</h2>
    <p>{post.content}</p>
    <button onclick={async () => await like_post(post.id)}>
      👍 {post.likes}
    </button>
  </div>
{/each}

Notice the import path: $lib/demo.remote. FluidKit generates demo.remote.ts next to your demo.py — this is a standard SvelteKit remote function file that proxies calls to your Python backend. You never need to edit it.

What just happened?

When you decorated functions with @query, @command, and @form, FluidKit:

  • Registered each function as a FastAPI endpoint — with parameter types, validation, and return types extracted automatically
  • Generated a .remote.ts file — a SvelteKit remote function wrapper that calls your FastAPI endpoint with full type safety
  • Wired up cache invalidationget_posts().refresh() inside like_post and add_post tells SvelteKit to refetch that query in the same round-trip

Next steps

  • @query — arguments, batching, refresh
  • @command — writing data, updating queries, optimistic updates
  • @form — fields, validation, file uploads, progressive enhancement
  • @prerender — build-time data with optional runtime fallback
  • CLI — all available commands
  • Configuration — fluidkit.config.json reference
FluidKit