FLIN = HTML + CSS
That's it. No new paradigms. No complex concepts.
If you know HTML and CSS, you already know 90% of FLIN.
<button>Click</button>.btn { color: blue }click={count++}Technologies Replaced by FLIN
Everything you used to install separately is now built-in.
Frontend
- React/Vue/Svelte → .flin files
- Material UI/Chakra → FlinUI (180 components)
- useState/Zustand → variables
- React Router → app/ folder
- Tailwind/CSS-in-JS → plain CSS
Backend
- Express/Fastify → route GET/POST
- Passport.js → guards
{ auth } - express-rate-limit → rate_limit()
- multer → file @image
Database
- PostgreSQL/MySQL → .flindb/ (WAL, CRC, locking)
- Prisma/Drizzle → entity + 49 validators
- Redis → built-in cache
- S3/Cloudinary → save_file()
Auth & Security
- NextAuth/Auth.js → auth_google_login()
- speakeasy/otplib → totp_verify()
- bcrypt/argon2 → bcrypt_hash()
- jsonwebtoken → jwt_create()
DevOps
- dotenv → env("KEY")
- PM2 → systemd (3 lines)
- webpack/vite → not needed
- Docker Compose → 1 Dockerfile
AI & Search
- OpenAI SDK → ask_ai()
- Pinecone/Weaviate → semantic search
- LangChain → ask ... about
- Elasticsearch → BM25 built-in
No package.json. No node_modules. No dependency hell. Just one binary that does everything.
JS/TS Developers: You Already Know 80%
FLIN accepts TypeScript type names, the function keyword, null, console.log, and .length. Use what you know on day one.
Works unchanged from JS/TS
// Type aliases entity User { name: string // = text age: number // = float active: boolean // = bool } // function keyword function greet(name: string) { return "Hello, " + name } // null works everywhere if user == null { return null } // console.log works console.log("debug info") // .length works on strings + lists name.length // 5 items.length // 3 // Also: let, const, ??, ++, +=, // try/catch, async/await
Only 3 things are different
// 1. Maps use ["key": val] not {} data = ["name": "Alice", "age": 30] // { name: "Alice" } gives helpful error // 2. Functions over methods push(items, x) // not items.push(x) map(arr, fn) // not arr.map(fn) json_decode(str) // not JSON.parse(str) // 3. No imports needed // Just use <Button> and User.all // Components + entities auto-discovered
If you write maps with curly braces, FLIN tells you to use bracket syntax instead. Helpful errors, not cryptic ones.
The Only 6 Things to Learn
Everything else is just HTML and CSS you already know.
Variables are Reactive
// Declare a variable count = 0 // It updates the UI automatically <span>{count}</span>
No useState, no signals, no stores. Just variables.
Events are Simple
// click, submit, change, input...
<button click={count++}>
Add
</button>
<form submit={save()}>
...
</form>Same events as HTML. Just add the action.
Two-Way Binding
name = "" // bind connects input to variable <input bind={name} /> // Shows what you type <p>Hello, {name}!</p>
No onChange handlers. Just bind.
Show/Hide with if
logged_in = false
{if logged_in}
<Dashboard />
{else}
<Login />
{/if}Just like every template language.
Loop with for
todos = ["Buy milk", "Code", "Sleep"]
{for todo in todos}
<li>{todo}</li>
{/for}Standard for loop. Nothing new.
Entities = Your Database
// Enums — type-safe, auto-validated enum Priority { Low, Medium, High } entity Todo { title: text @required @minLength(2) done: bool = false priority: Priority = "Low" @index(done, priority) } // Create, save, query todo = Todo { title: "Learn FLIN" } save todo Todo.where(done == false).count
Built-in database. No SQL. No setup. Just save.
That's it. Variables, events, bind, if, for, entities. The rest is HTML and CSS.
What You Already Know vs FLIN
HTML Structure
<div class="card"><div class="card">Exactly the same!
CSS Styling
.card { padding: 1rem }.card { padding: 1rem }Exactly the same!
Inline Styles
style="color: red"style="color: red"Exactly the same!
Dynamic Class
className={`btn ${active}`}class="btn {active}"Just use interpolation in class
Form Input
value={x} onChange={...}bind={x}One word instead of two
Click Handler
onClick={() => setX(x+1)}click={x++}Direct action, no wrapper
Build a Real App: Step by Step
A complete task manager in one file. This is real, working FLIN codefrom the official todo-embedded example.
Define Your Data
// entities/Todo.flin enum Priority { Low, Medium, High, Critical } enum Category { General, Work, Personal } entity Todo { title: text @required @minLength(2) done: bool = false priority: Priority = "Low" category: Category = "General" due: time @index(done, priority) @unique(title) } // 10 types, 49 validators, enums, constraints // Auto-adds: id, created_at, updated_at, version
No SQL. No migrations. No Prisma. Just declare your fields.
Write Your Functions
// Always type entity parameters!
fn toggleTask(task: Todo) {
task.done = !task.done
save task
}
fn deleteTask(task: Todo) {
delete task
}
fn getGrade(score: int) {
result = match score {
n if n >= 90 -> "A"
n if n >= 80 -> "B"
_ -> "C"
}
return result
}Functions with type annotations. Match expressions with guards. Simple.
Query Your Data
// Filter with match filter = "all" todos = match filter { "pending" -> Todo.where(done == false) "done" -> Todo.where(done == true) _ -> Todo.all } // Chain queries Todo.where(priority > 2) .order_by("created_at", "desc") .limit(10) // Aggregations Todo.count Todo.where(done == true).count
Readable queries. Chainable. Works in templates too.
Build Your UI
// Standard HTML with {curly braces}
<h1>Tasks ({Todo.count})</h1>
<form submit={add()}>
<input bind={newTitle} />
<button type="submit">Add</button>
</form>
{for task in todos}
<div class={task.done ? "done" : ""}>
<span>{task.title}</span>
<button click={toggleTask(task)}>
Toggle
</button>
</div>
{/for}HTML you know + FLIN curly braces. That's the whole UI layer.
Add Dark Mode & i18n
// Session persists to cookie theme = session.theme || "light" <div data-theme={theme}> <button click={ session.theme = theme == "light" ? "dark" : "light"; location.reload() }>Toggle Theme</button> </div> // i18n (translations auto-loaded) fn t(key) { dict = translations[session.lang || "en"] result = dict[key] return result ?? key }
Session variables survive page reloads. Built-in i18n.
Add an API Route
// app/api/todos.flin
route GET /api/todos {
todos = Todo.all
response.ok({ todos: todos })
}
route POST /api/todos {
guards { auth: required }
validate {
title: text @required @minLength(2)
priority: text @one_of("Low", "Medium", "High")
email: text @email
}
todo = Todo { title: body.title }
save todo
response.created(todo)
}REST API with guards and validation. Auto-generates OpenAPI docs.
Try it yourself: Run flin dev embedded/todo-app to see this exact pattern running live.Then check flin dev embedded/fullstack for the advanced version with auth, OAuth, and WebSocket.
380+ Built-in Functions
No npm install. No importing. Every function is global and ready to use.
Strings (35)
len("hello")uppercase("hi")split("a,b", ",")join(list, ", ")replace(s, "a", "b")trim(" hi ")starts_with(s, "http")slugify("Hello World")Math (35)
abs(-5)floor(3.7)ceil(3.2)round(3.14, 1)sqrt(16)pow(2, 10)random(1, 100)sum([1,2,3])Lists (34)
push(list, item)pop(list)sort(list)unique(list)filter(list, fn)map(list, fn)contains(list, x)flatten(nested)Date/Time (35)
now()today()time_format(t, "%Y-%m-%d")time_add(t, 7, "days")time_diff(a, b, "hours")time_is_weekend(t)parse_date("2026-01-15")time_to_iso(t)Crypto & Auth (30)
uuid()bcrypt_hash(pwd)bcrypt_verify(pwd, h)jwt_create(payload)sha256("data")aes_encrypt(data, key)totp_secret()totp_verify(s, code)Validation (20)
is_email("[email protected]")is_url("https://...")is_uuid(str)is_strong_password(p)matches_pattern(s, r)is_json(str)is_number("42")is_empty(val)Plus: HTTP client (http_get, http_post), file I/O (read_file, write_file), email (send_email), PDF (pdf_from_html), OAuth (Google, GitHub, Discord), jobs (job_queue, job_schedule), AI (ask_ai, semantic search), and more.
Explore all 380+ functions live: flin dev embedded/playground
The Real Secret: CSS is Your Superpower
Enterprise UIs aren't about fancy JavaScript frameworks.
They're about well-organized CSS.
Use CSS Variables
:root {
--primary: #d4a853;
--radius: 8px;
--shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.card {
border-radius: var(--radius);
box-shadow: var(--shadow);
}Change one variable, update entire app.
Use Flexbox & Grid
/* Flexbox for alignment */ .header { display: flex; gap: 1rem; } /* Grid for layouts */ .cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; }
Master these two and you can build anything.
Use Semantic Classes
/* Bad */ .red-text { color: red; } .big-margin { margin: 20px; } /* Good */ .error-message { color: var(--error); } .card-spacing { margin: var(--space-4); }
Name what it IS, not what it looks like.
Dark Mode in 5 Lines
[data-theme="dark"] {
--bg: #1a1a1a;
--text: #ffffff;
--border: #333;
}
/* FLIN: Toggle with one click */
<button click={theme = "dark"}>CSS does the work. FLIN just switches the variable.
507+ Ready-to-Copy Patterns
Every UI pattern you need is already documented with working code.Copy, don't reinvent.
Core (10 guides)
- Components
- Routing
- Layouts
- Styling
- State
- Deployment
UI & Forms (25 guides)
- FlinUI (180 components)
- Forms & Validation
- Modals & Dialogs
- Dropdowns & Tabs
- Toasts & Alerts
- Date/Color Pickers
Components (15 guides)
- Data Tables
- Card Grids
- Pagination
- Infinite Scroll
- Carousel
- Timeline
Auth & Security (10 guides)
- Login/Register
- OAuth (Google/GitHub)
- Two-Factor Auth
- WhatsApp OTP
- Guards & Roles
- Password Reset
Data & API (15 guides)
- CRUD Operations
- Queries & Filters
- REST API
- File Upload
- Search
- Time Travel
Special Features (30+ guides)
- i18n (Multi-language)
- Theme Toggle
- WebSockets
- AI Chat
- Shopping Cart
- PDF Generation
The 12-Year-Old Test
Every piece of FLIN code must be understandable by a 12-year-old who knows basic HTML.
If it's confusing, it's wrong. If it needs explanation, it needs simplification.
If you can't explain it simply, you don't understand it well enough.— Albert Einstein
A Real Example: Login Page
See how HTML knowledge directly translates to FLIN.
// Variables (reactive) email = "" password = "" error = "" // HTML you already know <div class="login-card"> <h1>Welcome Back</h1> {if error} <p class="error">{error}</p> {/if} <form submit={login()}> <input type="email" bind={email} placeholder="Email" /> <input type="password" bind={password} placeholder="Password" /> <button type="submit"> Sign In </button> </form> <p> Don't have an account? <a href="/register">Sign up</a> </p> </div>
What's Happening
The FLIN parts are just: variables, bind, if, submit.
Ready to Build?
Start with the embedded examples. See real code. Copy what works.
flin dev embedded/starterflin dev embedded/todo-appflin dev embedded/fullstackflin dev embedded/flinuiThe fullstack app includes: Auth, OAuth, 2FA, API routes, uploads, WebSocket, i18n, themes.FlinUI includes 180 components, 1,667 icons, charts, templates, and more.
Copy the code. Make it yours. No attribution needed.
Continue Learning
Master FLIN with our complete documentation atdocs.flin.dev
Variables & Reactivity
Learn how FLIN variables automatically update the UI.
Entities
Database models without SQL. Save, query, delete.
Views
HTML templates with interpolation and control flow.
Events
Handle clicks, submits, and user interactions.
