Back to flin
flin

Writing Apps Like It's 1995 With the Power of 2026

FLIN brings back the simplicity of 1995 web development with the power of a 2026 compiler, VM, and database.

Thales & Claude | March 25, 2026 13 min flin
flinsimplicityvisionweb-developmentnostalgiacomparison

In 1995, you created index.html, wrote

Hello

, uploaded it to a server, and it worked. The feedback loop was measured in seconds. A twelve-year-old could build a website in an afternoon. The entire web was built by people who were not professional programmers -- they were teachers, students, hobbyists, small business owners who needed a presence on this new thing called the internet.

In 2024, creating the equivalent of that hello world requires installing Node.js, initializing a project, installing React, ReactDOM, Vite, TypeScript, type definitions, Tailwind, PostCSS, Autoprefixer, ESLint, Prettier, and then creating a dozen configuration files before writing a single line of application code. The dependency count approaches 2,000 packages. The disk footprint exceeds 1.5 gigabytes. The time to first render is measured in hours.

FLIN exists because we believe this trajectory is not inevitable. It is a choice the industry made, and it is a choice we can unmake. Not by going backward to the limitations of 1995, but by going forward -- building a language that delivers the simplicity of that era with the full power of 2026: a compiler, a virtual machine, an embedded database, reactive UI, and an HTTP server. All behind a single file.

This article tells the story of that vision: where it came from, what it looks like in practice, and why the complexity of modern web development is not a natural law.

The Complexity Explosion: A Timeline

To understand FLIN's reason for existence, you need to see how we got here. The numbers are not exaggerated -- they are conservative.

Year    Files for "Hello World"    Dependencies    Config Files    Disk Space
----    -----------------------    ------------    ------------    ----------
1995    1 (index.html)             0               0               3 KB
2005    3 (HTML/CSS/JS)            0               0               15 KB
2010    10 + jQuery                5               1               500 KB
2015    50 + Gulp                  200             5               80 MB
2020    500 + Webpack              1,000           10              500 MB
2024    50,000+                    2,000           15+             1.5 GB

Each step in this progression was rational in isolation. jQuery solved cross-browser compatibility. Gulp solved build automation. Webpack solved module bundling. React solved UI state management. TypeScript solved type safety. Tailwind solved CSS utility classes. Each tool addressed a real problem.

But the aggregate effect is that the tools meant to help us have become the problem. A modern developer spends more time configuring tools than writing application code. The learning curve, once measured in days, now takes months. And in emerging markets -- where internet is slow, data is expensive, and power is unreliable -- downloading 1.5 GB of node_modules is not an inconvenience. It is a barrier to entry.

The Observation That Started FLIN

FLIN was born from a simple observation: most web applications do the same five things.

1. Display data to the user. 2. React to user input. 3. Save data to a database. 4. Query data from a database. 5. Handle HTTP requests.

Five things. And yet, to do these five things in 2024, you need React for the first, a state management library for the second, Prisma or TypeORM for the third and fourth, Express or Fastify for the fifth, plus TypeScript, Vite, ESLint, Prettier, Tailwind, and a dozen configuration files to wire them all together.

The question that launched FLIN was: what if a single tool did all five things natively?

Not a framework. Not a library. Not a "batteries-included" toolkit that still requires npm and Node.js under the hood. A programming language. One where reactivity, persistence, queries, and HTTP handling are built into the syntax itself, the way arithmetic and string operations are built into every language.

What FLIN Looks Like: The Simplest App

Here is a complete, working FLIN application. Not a toy. Not a "hello world" that leaves out the hard parts. A functional counter with a button that increments a number and displays it:

count = 0

```

Two lines of logic. One line of view. Save it as app.flin. Run flin dev. The browser opens. You click the button. The number goes up. There is no import statement, no configuration file, no build step, no package manager, no framework initialization.

Compare this with the React equivalent:

import { useState } from 'react';

export default function Counter() { const [count, setCount] = useState(0); return ( ); } ```

The React version requires understanding imports, the useState hook, arrow functions, JSX syntax, and the concept of a default export. The FLIN version requires understanding variables and HTML. A twelve-year-old who knows what

{for todo in filtered}

{todo.title}
{/for}

{Todo.where(done == false).count} items left
```

Forty-three lines. A complete application with a database-backed entity, reactive UI, filtering, creation, toggling, deletion, and a live count of remaining items. No configuration. No imports. No build tools. The entity keyword tells the FLIN compiler that Todo is a persistent data type stored in FlinDB. The save and delete keywords perform database operations. The {for ... in ...} block iterates over query results. The match expression selects the correct query based on the current filter.

To build the same application in React, you would need: React, a state management solution, a backend framework (Express or Next.js API routes), a database (PostgreSQL or SQLite), an ORM (Prisma or Drizzle), a CSS solution, and a build tool. The resulting codebase would span multiple files across frontend and backend directories, with configuration files for each tool.

The Power Behind the Simplicity

The simplicity of FLIN's syntax is not achieved by limiting its capabilities. It is achieved by moving complexity into the compiler and runtime, where it belongs. Behind every FLIN file is a four-phase compilation pipeline and a multi-component runtime.

When you write count = 0 in FLIN, the compiler does not simply store a number. It creates a reactive binding -- a variable that, when changed, automatically triggers UI updates in every view that references it. This is the same reactivity model that React, Vue, and Svelte implement with hooks, refs, and runes, respectively. The difference is that in FLIN, it is the default behavior. You do not opt into reactivity. Every variable is reactive.

When you write entity Todo { title: text }, the compiler generates a database schema, creates a table in FlinDB, registers query methods (Todo.all, Todo.where(...), Todo.find(...)), and sets up temporal tracking so that every record maintains its full history. One line of FLIN replaces the Prisma schema definition, the migration file, the model class, and the repository pattern.

When you write save todo, the runtime serializes the entity, writes it to FlinDB's WAL (Write-Ahead Log), updates the in-memory cache, invalidates any query caches that reference the Todo type, and triggers reactive updates in all views that display todo data. One keyword replaces an API call, a database transaction, a cache invalidation, and a state update.

FLIN Source          What the Compiler/Runtime Actually Does
-----------          ---------------------------------------
count = 0            Allocate reactive variable, register in dependency graph
entity Todo {...}    Generate schema, create table, register query methods,
                     enable temporal tracking
save todo            Serialize, WAL write, cache update, cache invalidation,
                     reactive UI update
Todo.where(...)      SQL query generation, parameter binding, result
                     deserialization, optional caching
{for todo in ...}    Virtual DOM diff, incremental list rendering,
                     keyed reconciliation

The developer writes five things. The compiler and runtime do fifty things. This is the bargain FLIN offers: you think about your application, and the toolchain thinks about everything else.

The Elimination List

When you adopt FLIN, you stop using an entire ecosystem of tools. This is not an abstract claim -- it is a concrete list.

On the frontend, FLIN's reactive views replace React, Vue, Svelte, and Angular. FLIN's file-based routing replaces Next.js, Nuxt, and SvelteKit. FLIN's reactive variables replace Redux, Zustand, and Pinia. FLIN's built-in data fetching replaces React Query and SWR.

On the backend, FLIN's route handlers replace Express, Fastify, and NestJS. FLIN's entity system replaces Prisma, TypeORM, and Drizzle. FlinDB replaces PostgreSQL, MySQL, Redis, Elasticsearch, and Pinecone.

In tooling, FLIN replaces npm, Webpack, Vite, TypeScript, ESLint, Prettier, Jest, and Docker.

In configuration, FLIN replaces package.json, tsconfig.json, vite.config.js, tailwind.config.js, .eslintrc, .prettierrc, postcss.config.js, docker-compose.yml, and .env files.

The numbers tell the story:

Metric              Node.js Stack    FLIN        Reduction
------              -------------    ----        ---------
Files (Hello World) 50,000+          1           99.998%
Dependencies        1,847            0           100%
Config files        15+              0           100%
Disk space          1.5 GB           ~50 KB      99.997%
Time to start       2 hours          2 minutes   98.3%

Why This Matters for Africa

FLIN was created in Abidjan, Cote d'Ivoire, and its design reflects the constraints of building software in West Africa.

When your internet connection averages 5 Mbps on a good day, downloading 1.5 GB of node_modules is not a five-minute wait -- it is a multi-hour ordeal that consumes expensive mobile data. When power outages interrupt your work, a long Webpack build that fails mid-compilation means starting over. When your laptop has 4 GB of RAM, running a development server alongside VS Code and a browser requires careful memory management that modern JavaScript toolchains casually ignore.

FLIN's zero-dependency model eliminates all of these friction points. There is nothing to download. There is no build step in development mode -- the compiler and runtime handle everything on the fly. The memory footprint is measured in megabytes, not gigabytes.

But the argument is broader than infrastructure constraints. The complexity of modern web development is a barrier to participation. A teenager in Dakar who wants to build a website encounters an ecosystem that demands months of study before producing anything meaningful. The gap between "I know HTML" and "I can build a web application" has widened from days to months.

FLIN closes that gap. If you know what

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles

Thales & Claude sh0

34 Rules to Catch Deployment Mistakes Before They Happen

We built a pure-Rust static analysis engine with 34 rules across 8 categories to catch security issues, misconfigurations, and deployment mistakes before they reach production.

12 min Mar 25, 2026
ruststatic-analysissecuritycode-health +2
Claude flin

FLIN: The Language That Replaces 47 Technologies

One language for frontend, backend, database, and tooling. Built from scratch in Rust with 3,200+ tests. No npm. No Webpack. No framework fatigue.

4 min Mar 25, 2026
flinrustprogramming-languagecompiler +2
Thales & Claude sh0

Auto-Detecting 19 Tech Stacks from Source Code

How sh0's build engine detects 19 tech stacks, generates production-grade Dockerfiles with multi-stage builds, and creates optimized build contexts -- all in pure Rust.

11 min Mar 25, 2026
ruststack-detectiondockerfilebuild-engine +2