¿Y si pudieras eliminar React, Next.js, Redux, Prisma, Express, Tailwind y 41 herramientas más -- y reemplazarlas todas con un único lenguaje de programación?
Esto no es un experimento mental. Es el objetivo de diseño de FLIN, y este artículo mapea cada tecnología que reemplaza, explica por qué cada reemplazo es posible y muestra el código que lo demuestra.
Contamos. El número es 47. No porque apuntáramos a un número grande, sino porque esa es la cantidad de herramientas distintas que el ecosistema moderno de JavaScript requiere para construir, estilizar, servir, persistir, buscar, probar, validar, formatear, empaquetar y desplegar una aplicación web de producción.
Aquí está la lista completa de eliminación.
Categoría 1: Frameworks de frontend
Eliminados: React, Vue, Svelte, Angular, Solid, Preact
Seis frameworks. Seis modelos de componentes diferentes. Seis sistemas de reactividad diferentes. Seis sintaxis de plantillas diferentes. Seis curvas de aprendizaje diferentes. Seis comunidades que no comparten código, convenciones ni modelos mentales.
FLIN reemplaza los seis con vistas reactivas integradas en el propio lenguaje:
flincount = 0
name = ""
<div>
<h1>Hello, {if name then name else "World"}!</h1>
<input placeholder="Your name" value={name}>
<button click={count++}>Clicked {count} times</button>
</div>No hay import React from 'react'. No hay etiqueta <script> envolviendo la lógica. No hay useState, ni ref(), ni $state, ni signal(). Las variables son reactivas porque el compilador de FLIN rastrea qué variables se usan en qué expresiones de vista y genera código de actualización de grano fino automáticamente.
La idea clave: en React, debes optar explícitamente por la reactividad (useState). En Vue, debes declarar explícitamente las referencias reactivas (ref). En FLIN, la reactividad es el comportamiento predeterminado. Escribes count = 0, y cada vista que referencia count se actualiza cuando cambia. El compilador se encarga del resto.
Compara el mismo contador en React:
jsx// React: 12 lines, 3 imports, 1 hook
import React, { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}Y en FLIN:
flin// FLIN: 4 lines, 0 imports, 0 hooks
count = 0
<button click={count++}>{count}</button>Cuatro líneas. Cero ceremonias. El mismo resultado.
Categoría 2: Meta-frameworks
Eliminados: Next.js, Nuxt, SvelteKit, Remix, Astro
Los meta-frameworks existen porque los frameworks de frontend resuelven solo la mitad del problema. React renderiza la UI, pero no gestiona el enrutamiento, el renderizado del lado del servidor, los endpoints de la API ni la generación estática. Next.js llena esa brecha para React. Nuxt la llena para Vue. SvelteKit la llena para Svelte.
FLIN no necesita un meta-framework porque es un lenguaje completo, no una biblioteca de UI. El enrutamiento se basa en archivos:
my-app/
index.flin --> /
about.flin --> /about
products/
index.flin --> /products
[id].flin --> /products/:id
api/
users.flin --> /api/users
users/[id].flin --> /api/users/:idLas rutas dinámicas usan sintaxis de corchetes. Los parámetros están disponibles a través del objeto params:
flin// products/[id].flin
product = Product.find(params.id)
{if product}
<h1>{product.name}</h1>
<p>{product.description}</p>
<span class="price">{product.price}</span>
{else}
<h1>Product not found</h1>
{/if}Las rutas de API usan la palabra clave route con declaraciones de métodos HTTP:
flin// api/users.flin
route GET {
User.where(active == true)
}
route POST {
user = User {
name: body.name,
email: body.email,
role: body.role || "user"
}
save user
user
}Sin Express. Sin Fastify. Sin cadena de middleware. Sin objetos request/response que desestructurar. La variable body es el cuerpo de la solicitud parseado. El valor de retorno es la respuesta JSON. FLIN gestiona la serialización, las cabeceras content-type y los códigos de estado HTTP automáticamente.
Categoría 3: Gestión de estado
Eliminados: Redux, Zustand, Pinia, MobX, Recoil, Jotai
Las bibliotecas de gestión de estado existen porque el modelo de componentes de React dificulta compartir estado entre componentes distantes. Redux por sí solo ha generado un sub-ecosistema entero: Redux Toolkit, Redux Saga, Redux Thunk, Redux Persist, React Redux.
FLIN elimina la categoría entera con una regla: todas las variables son reactivas por defecto.
flin// This is FLIN's entire state management solution
count = 0
userName = "Guest"
items = []
filter = "all"
// Computed values re-evaluate automatically
filtered = match filter {
"all" -> items
"active" -> items.where(x => x.done == false)
"completed" -> items.where(x => x.done == true)
}No hay store. No hay reducer. No hay action creator. No hay selector. No hay useDispatch. No hay useSelector. No hay wrapper Provider. Las variables existen a nivel de archivo, y cualquier expresión de vista que las referencia se actualiza cuando cambian.
Redux por sí solo requiere entender acciones, reducers, el store, middleware, selectores y la API de connect/hooks -- seis conceptos distintos para resolver un problema que, en FLIN, no requiere ningún concepto porque está integrado en el modelo de ejecución del lenguaje.
Categoría 4: Obtención de datos
Eliminados: React Query, SWR, TanStack Query, Apollo Client
Las bibliotecas de obtención de datos existen porque React no tiene forma nativa de obtener datos, cachearlos, invalidar cachés, gestionar estados de carga o reintentar solicitudes fallidas. React Query envuelve todo eso en hooks como useQuery y useMutation.
En FLIN, los datos provienen de entidades. Las entidades están respaldadas por FlinDB, la base de datos embebida de FLIN. No hay fetch, no hay estado de carga que gestionar, no hay caché que configurar:
flin// Data is just there
users = User.all
recentPosts = Post.order(created, "desc").limit(10)
activeProducts = Product.where(active == true)
// Filtering is reactive
searchQuery = ""
results = if searchQuery.len > 3 then
search searchQuery in Product by description limit 20
else
Product.allLa "biblioteca" de obtención de datos es el propio lenguaje.
Categoría 5: Frameworks CSS
Eliminados: Tailwind CSS, Styled Components, CSS Modules, Emotion, Sass
FLIN adopta un enfoque pragmático para el estilizado. Puedes usar CSS puro -- el lenguaje no impone una solución específica de estilizado. Pero la biblioteca de componentes planificada de FLIN, Elephant UI, proporcionará más de 70 componentes preconstruidos diseñados para el lenguaje.
Más importante aún, FLIN elimina la cadena de herramientas que los frameworks CSS requieren. Tailwind necesita PostCSS, un archivo de configuración y un paso de compilación para purgar clases no utilizadas. Styled Components necesita un plugin de Babel. Sass necesita un compilador. En FLIN, los estilos son simplemente CSS -- sin preprocesador, sin plugin, sin configuración:
flin<div class="container">
<h1 class="title">Products</h1>
{for product in products}
<div class="card" style="border-color: {product.color}">
<h3>{product.name}</h3>
<span class="price">{product.price}</span>
</div>
{/for}
</div>La capa de estilizado es intencionalmente simple. La filosofía de FLIN es que el presupuesto de complejidad debe gastarse en lógica de aplicación, no en elegir entre siete formas diferentes de aplicar un color de fondo.
Categoría 6: Frameworks de backend
Eliminados: Express, Fastify, Koa, Hono, NestJS
Cinco frameworks de backend, cada uno con diferentes sistemas de middleware, diferentes APIs de enrutamiento, diferentes ecosistemas de plugins. FLIN los reemplaza todos con declaraciones de rutas:
flin// api/users/[id].flin
route GET {
User.find(params.id)
}
route PUT {
user = User.find(params.id)
user.name = body.name || user.name
user.email = body.email || user.email
user.role = body.role || user.role
save user
user
}
route DELETE {
user = User.find(params.id)
delete user
{ success: true }
}Cada manejador de ruta es un bloque que recibe params (parámetros de URL) y body (cuerpo de la solicitud) como variables implícitas. El valor de retorno se convierte en la respuesta JSON. El manejo de errores, la serialización y la semántica HTTP son gestionados por el runtime de FLIN.
Compara esto con el equivalente en Express:
javascript// Express: 35+ lines, router setup, middleware, error handling
const express = require('express');
const router = express.Router();
router.get('/:id', async (req, res) => {
try {
const user = await prisma.user.findUnique({
where: { id: req.params.id }
});
if (!user) return res.status(404).json({ error: 'Not found' });
res.json(user);
} catch (err) {
res.status(500).json({ error: err.message });
}
});
// ... repeat for PUT, DELETELa versión de FLIN es más corta, más legible y gestiona los mismos casos. La diferencia no es azúcar sintáctico -- es la eliminación de una capa entera de abstracción.
Categoría 7: Base de datos y ORM
Eliminados: configuración de PostgreSQL, configuración de MySQL, Prisma, TypeORM, Drizzle, Mongoose
Aquí es donde brilla el principio de diseño "nativo de memoria" de FLIN. En el stack tradicional, necesitas: un servidor de base de datos (PostgreSQL o MySQL), una biblioteca de conexión, un ORM o constructor de consultas, una herramienta de migración y un lenguaje de definición de esquema.
FLIN reemplaza todo eso con la palabra clave entity y FlinDB, su base de datos embebida:
flinentity User {
name: text
email: text
role: text = "user"
active: bool = true
created: time = now
}
// Create
save User { name: "Juste", email: "[email protected]" }
// Read
users = User.all
admins = User.where(role == "admin")
firstUser = User.where(email == "[email protected]").first
// Update
user = User.find(id)
user.name = "Juste A. GNIMAVO"
save user
// Delete
delete userSin prisma migrate dev. Sin sentencias CREATE TABLE. Sin cadena de conexión en un archivo .env. La declaración entity es simultáneamente: una definición de tipo, una tabla de base de datos, un conjunto de operaciones CRUD y un rastreador de historial. Cuando escribes entity User, el runtime de FLIN crea la tabla, genera las consultas y gestiona la conexión -- todo de forma invisible.
El equivalente en Prisma requiere un archivo schema.prisma, una migración, un paso prisma generate y luego código como prisma.user.findMany({ where: { role: 'admin' } }). El User.where(role == "admin") de FLIN hace lo mismo sin configuración.
Categoría 8: Búsqueda
Eliminados: Elasticsearch, Algolia, Meilisearch, Pinecone, Weaviate
La búsqueda es una de las funcionalidades operativamente más costosas en un stack tradicional. La búsqueda de texto completo requiere Elasticsearch (una aplicación Java que necesita su propio clúster). La búsqueda semántica requiere una base de datos vectorial como Pinecone o Weaviate, más un pipeline de embeddings.
FLIN integra ambas en FlinDB:
flinentity Product {
name: text
description: semantic text // Auto-embedded for vector search
price: money
category: text
}
// Traditional filter
cheap = Product.where(price < 1000)
// Semantic search (vector similarity)
results = search "comfortable ergonomic office chair"
in Product
by description
limit 10
// Intent-based (natural language to query)
trending = ask "products added this week with price under 5000"El modificador semantic en un campo de texto indica a FlinDB que calcule automáticamente embeddings vectoriales. La palabra clave search realiza búsqueda por similitud contra esos embeddings. La palabra clave ask traduce lenguaje natural a consultas de base de datos usando IA.
Sin clúster de Elasticsearch. Sin clave API de Pinecone. Sin pipeline de embeddings. Sin gestión de índices. Una palabra clave en la definición de una entidad.
Categoría 9: Herramientas de compilación
Eliminados: Webpack, Vite, Parcel, Rollup, esbuild, Turbopack
Seis empaquetadores. Cada uno con su propio formato de configuración, su propio sistema de plugins, sus propias opiniones sobre división de código, tree shaking y resolución de módulos.
FLIN elimina la categoría por completo:
bashflin dev # Start development server
flin build # Production buildDos comandos. Cero configuración. El compilador de FLIN gestiona la tokenización, el análisis sintáctico, la verificación de tipos y la generación de código en una sola pasada. No hay un "paso de compilación" separado porque el compilador es la herramienta de compilación.
El archivo de configuración de Vite para un proyecto típico de React tiene 30-50 líneas. Una configuración de Webpack puede superar las 200. La configuración equivalente de FLIN es: nada. No hay archivo de configuración porque no hay nada que configurar.
Categoría 10: Gestores de paquetes
Eliminados: npm, yarn, pnpm, bun (como gestor de paquetes)
Cuatro gestores de paquetes, cada uno resolviendo el mismo problema -- descargar y gestionar dependencias -- con diferentes formatos de lockfile, diferentes algoritmos de resolución y diferentes características de rendimiento.
FLIN no necesita un gestor de paquetes porque FLIN tiene cero dependencias. Todo está integrado. No hay node_modules. No hay package.json. No hay lockfile. No hay advertencia de npm audit sobre 47 vulnerabilidades de alta severidad en paquetes que nunca has oído nombrar.
Las implicaciones solo para el espacio en disco son asombrosas:
Herramienta tamaño node_modules Equivalente FLIN
----------- ----------------- ---------------
create-react-app ~300 MB 0 bytes
Next.js starter ~400 MB 0 bytes
Nuxt starter ~350 MB 0 bytes
Angular starter ~500 MB 0 bytesPara un desarrollador en Abiyán que paga por megabyte de datos, la eliminación de node_modules no es una comodidad. Es la diferencia entre poder trabajar y no poder trabajar.
Categoría 11: Sistema de tipos
Eliminado: TypeScript (como herramienta separada)
TypeScript es posiblemente la adición más exitosa al ecosistema JavaScript. Detecta errores en tiempo de compilación, permite mejores herramientas y hace que las bases de código grandes sean manejables.
Pero TypeScript es un compilador separado con su propio archivo de configuración (tsconfig.json), sus propias reglas de resolución de módulos, sus propios conflictos de versión y su propia curva de aprendizaje. FLIN integra la verificación de tipos en el lenguaje:
flin// Types are inferred
name = "Juste" // text
age = 25 // int
price = 99.99 // number
active = true // bool
items = [1, 2, 3] // [int]
// Or declared explicitly
score: number = 0
nickname: text? = none // Optional textEl sistema de tipos de FLIN es más simple que el de TypeScript -- deliberadamente. No hay genéricos, ni tipos condicionales, ni tipos mapeados, ni tipos de plantillas literales. El sistema de tipos de FLIN cubre el 95% de los casos que el 95% de las aplicaciones necesitan. El 5% restante es complejidad que la filosofía de FLIN rechaza.
Categoría 12: Herramientas de calidad de código
Eliminados: ESLint, Prettier, Biome
Tres herramientas (o su sucesor, Biome) para validación, formateo y aplicación de estilo de código. Cada una con su propio archivo de configuración, sus propias reglas, su propio sistema de plugins.
El compilador de FLIN incluye un formateador integrado sin configuración. Hay una sola forma de formatear código FLIN, tal como hay una sola forma de formatear código Go (gofmt) o una sola forma de formatear código Rust (rustfmt). Los debates sobre tabulaciones versus espacios, punto y coma versus sin punto y coma, y comillas simples versus dobles no existen en FLIN porque el lenguaje toma esas decisiones por ti.
Categoría 13: Pruebas
Eliminados: Jest, Vitest, Mocha, Cypress, Playwright
FLIN incluye un ejecutor de pruebas integrado. Las pruebas son parte del lenguaje, no una herramienta externa con su propio archivo de configuración, su propia biblioteca de aserciones y su propia resolución de módulos.
El diseño sigue el mismo principio de cero configuración: escribe pruebas, ejecuta flin test, ve los resultados. Sin jest.config.js. Sin vitest.config.ts. Sin decisión sobre qué ejecutor de pruebas usar.
Categoría 14: Archivos de configuración eliminados
Esta categoría merece su propia sección porque representa el síntoma más visible del problema de las 47 herramientas:
Archivo de config eliminado Propósito
--------------------------- -----------------------------------
package.json Metadatos y scripts del paquete
package-lock.json Lockfile de dependencias
tsconfig.json Configuración de TypeScript
vite.config.ts Configuración del empaquetador
webpack.config.js Configuración del empaquetador
tailwind.config.js Configuración del framework CSS
postcss.config.js Configuración del procesamiento CSS
babel.config.js Transpilación de JavaScript
.eslintrc.js Configuración del linter
.prettierrc Configuración del formateador
jest.config.js Configuración del ejecutor de pruebas
next.config.js Configuración del meta-framework
nuxt.config.js Configuración del meta-framework
svelte.config.js Configuración del meta-framework
docker-compose.yml Orquestación de contenedores
.env / .env.local / .env.prod Variables de entornoDieciséis archivos de configuración, eliminados. No ocultos detrás de los valores predeterminados de un framework. Eliminados por completo, porque la herramienta que configuraban ya no existe.
El marcador final
| Métrica | Antes (ecosistema Node.js) | Después (FLIN) | Reducción |
|---|---|---|---|
| Archivos para Hello World | 50.000+ | 1 | 99,998% |
| Dependencias | 1.847 | 0 | 100% |
| Archivos de config | 15+ | 0 | 100% |
| Espacio en disco | 1,5 GB | ~50 KB | 99,997% |
| Tiempo para empezar a codificar | 2+ horas | 2 minutos | 98,3% |
| Curva de aprendizaje | Meses | Días | ~90% |
| Herramientas que aprender | 47 | 1 | 97,9% |
Estas no son proyecciones. Son los objetivos de diseño para los que cada decisión en la arquitectura de FLIN está optimizada.
Lo que FLIN no reemplaza
La honestidad intelectual requiere listar lo que FLIN conserva:
- CSS -- Puedes usar cualquier framework CSS junto a FLIN, o escribir CSS puro. El estilizado no es una preocupación del lenguaje.
- Git -- El control de versiones es ortogonal al lenguaje de programación.
- Tu editor -- VS Code, Vim, Emacs -- FLIN funciona con cualquier editor de texto.
- Plataformas de despliegue -- Aún necesitas algún lugar para ejecutar el binario, aunque la salida de binario único de FLIN hace el despliegue trivialmente simple.
FLIN reemplaza las herramientas que se interponen entre tu idea y una aplicación funcional. No reemplaza las herramientas que existen fuera de ese límite.
El argumento filosófico
Cuarenta y siete tecnologías no es un número que nadie eligió. Es el resultado emergente de un ecosistema donde cada problema se resuelve añadiendo una nueva herramienta, y nadie es responsable del total. npm tiene 2,5 millones de paquetes no porque se necesiten 2,5 millones de paquetes, sino porque el coste de crear un nuevo paquete es menor que el coste de mejorar uno existente.
FLIN apuesta por la filosofía opuesta: una herramienta, propiedad de un equipo, responsable del stack completo. Cuando el sistema de entidades tiene un error, lo corregimos. No abrimos un issue en el GitHub de Prisma y esperamos a un mantenedor voluntario. Cuando el enrutador necesita una funcionalidad, la añadimos. No evaluamos cinco paquetes de middleware de Express en competencia.
Esto es un compromiso. FLIN nunca tendrá la amplitud de ecosistema de npm. Pero tendrá algo que npm no puede proporcionar: coherencia. Cada funcionalidad en FLIN fue diseñada para funcionar con cada otra funcionalidad, probada en conjunto, versionada en conjunto, documentada en conjunto.
Cuarenta y siete herramientas, cada una excelente de forma aislada, crean una experiencia fragmentada. Un lenguaje, diseñado como un todo, crea una experiencia unificada.
Esa es la apuesta.
Siguiente en la serie: Naming a Language After an Elephant: The Fongbe Origin of FLIN -- En fongbe, una lengua hablada en Benín, hay una frase: "E flin nu" -- "Recuerda las cosas."