La inteligencia artificial está transformando la forma en que desarrollamos software. Hoy es posible generar un CRUD completo en pocos minutos utilizando herramientas como ChatGPT, Claude, Gemini y otras plataformas de IA.
En ese contexto surge una pregunta estratégica: ¿qué stack tecnológico consume menos tokens y ofrece mayor productividad en la generación de código?
Esta cuestión importa porque el consumo de tokens impacta directamente en el costo de uso de la IA, la velocidad de generación, la claridad de las respuestas, la facilidad de mantenimiento y la cantidad de contexto disponible para las reglas de negocio.
Qué son los tokens
Los tokens son las unidades de texto procesadas por los modelos de lenguaje. Cada modelo tiene un presupuesto finito de tokens por solicitud, y todo lo que lee o produce consume parte de ese presupuesto.
- Palabras enteras o fragmentos de palabras.
- Símbolos y signos de puntuación.
- Fragmentos de código fuente, con nombres de variables, tipos y estructuras.
- Espacios, saltos de línea e indentación.
Cuanto más extenso y verboso sea el código, mayor será el consumo de tokens. Los frameworks que exigen mucho boilerplate o decoradores extensos agotan el presupuesto antes incluso de que aparezca la regla de negocio.
Por qué esto importa
Al desarrollar aplicaciones con apoyo de IA, parte del presupuesto de tokens se consume en la estructura del propio código. Los stacks más concisos ofrecen ventajas directas para el equipo de ingeniería.
- Menor costo operativo en llamadas a la API del modelo.
- Respuestas más rápidas, porque el contexto enviado es menor.
- Menor necesidad de dividir los prompts en varios pasos.
- Más espacio para describir reglas de negocio y requisitos específicos.
“Cuantos menos tokens consume la infraestructura, más tokens quedan para lo que realmente genera valor para el negocio.”
Metodología del benchmark
Para que la comparación sea justa, definimos un escenario estándar que cualquier stack debe entregar: un CRUD completo para la entidad Customer, con reglas de negocio explícitas y endpoints REST estandarizados.
La entidad Customer tiene los siguientes campos:
- id
- name
- document
- phone
- status
- created_at
- updated_at
Los endpoints REST esperados son:
- POST /customers, crea un nuevo cliente.
- GET /customers, lista los clientes con paginación.
- GET /customers/:id, recupera un cliente específico.
- PUT /customers/:id, actualiza los datos del cliente.
- DELETE /customers/:id, elimina el cliente.
Reglas de negocio que cada implementación debe garantizar:
- El campo name es obligatorio.
- El email debe ser único entre los clientes.
- El document debe ser único entre los clientes.
- El status solo acepta los valores active o inactive.
- El listado devuelve resultados paginados.
- Los errores se estandarizan en respuestas JSON.
Stacks evaluados
Nueve stacks pasaron por el mismo prompt, abarcando desde ecosistemas donde el CRUD es el caso de uso central hasta lenguajes cuya fortaleza está en otro tipo de servicio. La diversidad fue intencional: queríamos ver si los stacks tradicionalmente asociados al CRUD realmente pagan dividendos cuando la IA es quien tipea.
- PHP con Laravel.
- Python con Django y Django REST Framework.
- Bun con Elysia y Drizzle.
- Bun con Hono y Drizzle.
- TypeScript con NestJS y Prisma.
- Java con Spring Boot y JPA.
- C# con ASP.NET Core y Entity Framework Core.
- Go con Fiber y Ent.
- Go con Gin y GORM.
Los criterios de este benchmark se dividen en tres grupos, separados por cómo se evaluó cada uno:
- Medidos directamente a partir de la respuesta del modelo: total de tokens consumidos en la generación, líneas de código producidas y cantidad de archivos generados.
- Evaluados cualitativamente en este artículo: adherencia del código al funcionamiento real, basada en una revisión línea por línea de los outputs para identificar cuánto retrabajo pediría cada stack.
- Reservados para el próximo ciclo: tiempo de implementación hasta el primer despliegue local y complejidad de mantenimiento a largo plazo, ambos requieren ejecución del código y múltiples iteraciones.
Resultado del benchmark
Ejecutamos el benchmark localmente con Qwen 2.5 Coder 14B mediante Ollama en un MacBook Pro. Cada stack se ejecutó tres veces para neutralizar la varianza natural del modelo, y el número reportado es la mediana de tokens de salida producidos durante la generación de código.
- 1. Python con Django y Django REST Framework — 681 tokens, 92 líneas, 6 archivos
- 2. PHP con Laravel — 725 tokens, 138 líneas, 5 archivos
- 3. Bun con Elysia y Drizzle — 1.205 tokens, 145 líneas, 7 archivos
- 4. Go con Gin y GORM — 1.247 tokens, 186 líneas, 5 archivos
- 5. Go con Fiber y Ent — 1.317 tokens, 211 líneas, 5 archivos
- 6. TypeScript con NestJS y Prisma — 1.393 tokens, 209 líneas, 9 archivos
- 7. Java con Spring Boot y JPA — 1.514 tokens, 281 líneas, 7 archivos
- 8. Bun con Hono y Drizzle — 1.587 tokens, 200 líneas, 8 archivos
- 9. C# con ASP.NET Core y Entity Framework Core — 1.981 tokens, 341 líneas, 7 archivos
Saltan a la vista cuatro conclusiones. Primero, el podio muestra que los stacks donde el CRUD es el caso de uso central, con convención fuerte y generación implícita de rutas, gastan significativamente menos tokens. Django lideró con 681 tokens gracias al ModelViewSet de DRF, que sustituye cinco rutas REST por una sola clase. Laravel quedó en segundo, a apenas 44 tokens de distancia, con Route::apiResource cumpliendo un papel equivalente.
Segundo, la diferencia entre el primero y el último fue de casi tres veces el consumo. C# con ASP.NET Core y Entity Framework Core terminó en noveno con 1.981 tokens — resultado directo del estilo verboso de la plataforma .NET, con DTOs separados, DataAnnotations explícitas, repositorios formalizados y un Program.cs configurado con builder pattern. Todo eso es ergonomía para el equipo, pero cuesta caro cuando la IA es la que tipea.
Tercero, los stacks Go quedaron en la zona media del ranking, no en el tope. Convenciones explícitas, parsing manual y manejo individual de errores en cada handler suman tokens. Go es una elección excelente para servicios de infraestructura o APIs de alto rendimiento, pero el dominio típico del CRUD favorece a lenguajes con más convención.
Cuarto, NestJS quedó en sexto con 1.393 tokens, una posición mejor que lo que el peso aparente de sus decoradores y módulos sugeriría. La estructura es repetitiva, pero sustituye código de inicialización y ruteo que otros stacks deben describir explícitamente. En términos de tokens absolutos por entidad, se sostiene. El peso real de NestJS aparece cuando crece el número de entidades — volveremos a ese punto en el análisis de complejidad.
Top 3 destacado en morado. Modelo: Qwen 2.5 Coder 14B vía Ollama.
Django con DRF: el líder del benchmark
Django dominó el benchmark con 681 tokens, resultado directo de Django REST Framework. ModelViewSet sustituye las cinco rutas REST por una sola clase; DefaultRouter expone el conjunto completo con dos líneas en urls.py. Es lo que ocurre cuando el framework fue diseñado en torno al CRUD y la IA puede aprovechar esas convenciones sin reinventar la rueda.
- ModelViewSet automatiza listar, crear, recuperar, actualizar y eliminar sin código adicional.
- DefaultRouter expone todas las rutas REST a partir de un único register.
- ModelSerializer infiere campos a partir del model, eliminando duplicación.
- Migraciones automáticas vía makemigrations y migrate.
En el benchmark, Django entregó una ViewSet de cuatro líneas que cubre todo el CRUD:
from rest_framework import viewsets
from .models import Customer
from .serializers import CustomerSerializer
class CustomerViewSet(viewsets.ModelViewSet):
queryset = Customer.objects.all()
serializer_class = CustomerSerializerEl router completa el trabajo en otras tres líneas, sin necesidad de declarar cada endpoint individualmente:
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import CustomerViewSet
router = DefaultRouter()
router.register(r'customers', CustomerViewSet)
urlpatterns = [path('', include(router.urls))]Laravel: el benchmark clásico
Laravel quedó en segundo con 725 tokens, a apenas 44 de distancia de Django. Una sola línea crea todas las rutas REST de un recurso, y el ecosistema entrega prácticamente todo lo que un CRUD necesita: validación, migraciones, ORM, autenticación y pruebas.
- Convenciones maduras que reducen decisiones repetitivas.
- CLI potente para generar controllers, models y migrations.
- Eloquent como ORM robusto y expresivo.
- Gran ecosistema con paquetes consolidados.
En el benchmark, Laravel generó el ruteo completo en una sola línea de código. Toda la definición de los cinco endpoints REST cabe aquí:
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\API\CustomerController;
Route::apiResource('customers', CustomerController::class);El controller que da vida a esas rutas es igualmente conciso, delegando la validación a Form Requests y la serialización a Resources:
class CustomerController extends Controller
{
public function index(Request $request)
{
$page = $request->input('page', 1);
$pageSize = $request->input('pageSize', 10);
return CustomerResource::collection(
Customer::paginate($pageSize, ['*'], 'page', $page)
);
}
public function store(CustomerRequest $request)
{
$customer = Customer::create($request->validated());
return new CustomerResource($customer);
}
public function show(Customer $customer)
{
return new CustomerResource($customer);
}
public function update(CustomerRequest $request, Customer $customer)
{
$customer->update($request->validated());
return new CustomerResource($customer);
}
public function destroy(Customer $customer)
{
$customer->delete();
return response()->json(null, 204);
}
}Bun con Elysia y Drizzle: tipado moderno en TypeScript
Bun combina un runtime moderno con soporte nativo para TypeScript. Elysia ofrece una API extremadamente concisa para definir rutas y validaciones, y Drizzle mantiene el acceso a la base de datos tipado, ligero y cercano al SQL.
- Código conciso, con pocas líneas para exponer una ruta completa.
- Excelente inferencia de tipos de extremo a extremo.
- Alto rendimiento en el runtime de Bun.
- Bajo overhead de boilerplate y decoradores.
En el benchmark, las cinco rutas del CRUD se encadenan en un único objeto Elysia, sin decoradores ni archivos extra de ruteo:
import { Elysia } from 'elysia';
import { CustomerService } from '../services/CustomerService';
const customerService = new CustomerService();
export const customersRoute = new Elysia()
.post('/', async ({ body }) => {
return await customerService.create(body);
})
.get('/', async ({ query }) => {
const page = parseInt(query.page ?? '1', 10);
const pageSize = parseInt(query.pageSize ?? '10', 10);
return await customerService.list(page, pageSize);
})
.get('/:id', async ({ params }) => {
return await customerService.get(params.id);
})
.put('/:id', async ({ params, body }) => {
return await customerService.update(params.id, body);
})
.delete('/:id', async ({ params }) => {
await customerService.delete(params.id);
return { success: true };
});Go con Ent: productividad mediante generación de código
Go es tradicionalmente más explícito que los lenguajes dinámicos, pero Ent reduce significativamente el boilerplate. Al definir el schema de la entidad, gran parte de las operaciones de CRUD se generan automáticamente, con tipos fuertes y queries seguras.
Esto acerca a Go a la productividad de frameworks más opinados, sin renunciar a binarios simples y alto rendimiento en producción. Aun así, quedó en la zona media de la tabla con 1.317 tokens: cada handler tiene que manejar explícitamente el parsing, la validación y el tratamiento de errores, sin el azúcar sintáctico de frameworks dedicados al CRUD. Go es una elección excelente para servicios de infraestructura o APIs de alto rendimiento — para CRUD de aplicación, otros stacks pagan menos tokens por una estructura equivalente.
func (h *CustomerHandler) Create(c *fiber.Ctx) error {
var input struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Document string `json:"document" validate:"required"`
Phone string `json:"phone,omitempty"`
Status string `json:"status,omitempty"`
}
if err := c.BodyParser(&input); err != nil {
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid input",
"message": err.Error(),
})
}
customer, err := h.client.Customer.Create().
SetName(input.Name).
SetEmail(input.Email).
SetDocument(input.Document).
SetPhone(input.Phone).
SetStatus(input.Status).
Save(context.Background())
if err != nil {
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
"error": "Failed to create customer",
"message": err.Error(),
})
}
return c.JSON(customer)
}NestJS con Prisma: arquitectura corporativa
NestJS es excelente para sistemas complejos y equipos grandes. Decoradores, módulos e inyección de dependencias crean una arquitectura previsible, y sería razonable esperar que este overhead arquitectural pagara caro en tokens.
- Arquitectura consistente entre módulos y features.
- Separación clara de responsabilidades entre controllers, services y repositories.
- Fuerte adherencia a patrones corporativos y DDD.
- Ecosistema maduro de integraciones y pruebas.
Los números mostraron lo contrario. NestJS quedó en sexto lugar con una mediana de 1.393 tokens, cerca del medio de la tabla. Los decoradores son repetitivos, pero sustituyen código de inicialización y ruteo que otras stacks tienen que describir explícitamente — y la IA aprovecha ese patrón para generar handlers compactos:
@Controller('customers')
export class CustomerController {
constructor(private readonly customerService: CustomerService) {}
@Post()
async create(@Body() dto: CreateCustomerDto) {
try {
const created = await this.customerService.create(dto);
return { data: created };
} catch (error) {
return { error: true, message: error.message };
}
}
@Get()
async findAll(
@Query('page') page: number,
@Query('pageSize') pageSize: number,
) {
return { data: await this.customerService.findAll(page, pageSize) };
}
@Get(':id')
async findOne(@Param('id') id: string) {
return { data: await this.customerService.findOne(id) };
}
@Put(':id')
async update(
@Param('id') id: string,
@Body() dto: UpdateCustomerDto,
) {
return { data: await this.customerService.update(id, dto) };
}
@Delete(':id')
async remove(@Param('id') id: string) {
return { data: await this.customerService.remove(id) };
}
}Spring Boot con JPA: el enterprise de la JVM
Spring Boot quedó en séptimo lugar con 1.514 tokens. JpaRepository elimina parte del trabajo — la interfaz vacía gana automáticamente findAll, findById, save y delete — pero el resto del ecosistema cobra su precio en ergonomía explícita: anotaciones en cada propiedad de la entidad, getters y setters obligatorios en Java tradicional, configuración separada de DataSource y capa de service inyectada formalmente vía @Autowired. A cambio, el equipo recibe un framework con décadas de adherencia al mundo corporativo.
package com.example.demo.repository;
import com.example.demo.model.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.UUID;
public interface CustomerRepository extends JpaRepository<Customer, UUID> {
}El controller equivalente mantiene el patrón Spring de inyección vía @Autowired y ruteo vía @RequestMapping. Cada handler describe explícitamente el método HTTP y el tipo de retorno:
@RestController
@RequestMapping("/customers")
public class CustomerController {
@Autowired
private CustomerService customerService;
@GetMapping
public Page<Customer> getAllCustomers(Pageable pageable) {
return customerService.getAllCustomers(pageable);
}
@PostMapping
public ResponseEntity<Customer> createCustomer(@RequestBody Customer customer) {
Customer created = customerService.createCustomer(customer);
return ResponseEntity.created(null).body(created);
}
@PutMapping("/{id}")
public ResponseEntity<Customer> updateCustomer(
@PathVariable UUID id,
@RequestBody Customer customerDetails
) {
return ResponseEntity.ok(customerService.updateCustomer(id, customerDetails));
}
}ASP.NET Core con EF Core: lo verboso por diseño
C# con ASP.NET Core y Entity Framework Core terminó en noveno lugar con 1.981 tokens, casi tres veces el consumo de Django. Esto no es necesariamente una crítica: la plataforma .NET tradicionalmente prioriza expresividad, separación rígida de responsabilidades y validación declarativa vía DataAnnotations. Cada una de esas decisiones suma tokens a la generación.
- DTOs separados para creación, actualización y lectura, todos con sus propias anotaciones de validación.
- Repository pattern formal con interfaz dedicada e implementación inyectada vía DI.
- OnModelCreating en el DbContext para configurar comportamientos del EF Core.
- Program.cs con builder pattern, registro de servicios y configuración del pipeline HTTP.
El resultado es código altamente estructurado, pero la IA debe describir cada una de esas piezas explícitamente para entregar el CRUD. La diferencia respecto a Django, que hace casi todo vía ModelViewSet, queda visible en el Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<CustomerDbContext>(options =>
{
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"));
});
builder.Services.AddScoped<ICustomerRepository, CustomerRepository>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();El papel del framework
El lenguaje es solo parte de la ecuación. El mayor impacto en el consumo de tokens proviene de las decisiones del framework elegido.
- Convenciones que evitan reescribir la misma estructura en cada feature.
- Generación automática de código a partir de schemas o definiciones.
- Nivel de abstracción elegido para encapsular reglas comunes.
- Verbosidad exigida por la arquitectura de referencia del framework.
En muchos casos, el framework influye más en el presupuesto de tokens que el lenguaje en sí. Cambiar de framework dentro del mismo lenguaje puede reducir el consumo a la mitad.
“Cada archivo extra que tu arquitectura exige es un impuesto invisible sobre cada conversación con la IA.”
La complejidad del consumo de tokens
El benchmark midió un caso puntual: una entidad Customer con siete campos. Los sistemas reales no tienen una entidad, tienen docenas. Vale formalizar cómo crece ese consumo de tokens cuando entran N entidades en el alcance, porque ahí es donde aparece la diferencia entre una decisión técnica trivial y una decisión estratégica.
Para todos los stacks evaluados, el consumo de tokens para generar un sistema con N entidades es aproximadamente lineal en N:
“T(N) ≈ a + b × N”
Donde a es el costo fijo de boilerplate (configuración de base de datos, bootstrap del servidor, módulo raíz) y b es el costo marginal por entidad (migration, model, controller, validación, ruta). En notación Big O, esto es O(N): el crecimiento es proporcional al número de entidades, sin términos cuadráticos ni exponenciales. La buena noticia es que la linealidad implica previsibilidad; la mala es que la pendiente b cobra su precio con cada entidad nueva.
Estimando a y b a partir de la proporción de archivos fijos frente a archivos por entidad en el benchmark, y aplicando esos valores a los tokens medidos con N=1, llegamos a los siguientes parámetros y proyecciones para un sistema con diez entidades:
- Django con DRF:
a ≈ 40tokens,b ≈ 640tokens por entidad. Proyección paraN=10: alrededor de 6.440 tokens. - Laravel:
a ≈ 25,b ≈ 700. Proyección paraN=10: alrededor de 7.025 tokens. - Bun con Elysia y Drizzle:
a ≈ 170,b ≈ 1.035. Proyección paraN=10: alrededor de 10.520 tokens. - Go con Gin y GORM:
a ≈ 140,b ≈ 1.107. Proyección paraN=10: alrededor de 11.210 tokens. - Go con Fiber y Ent:
a ≈ 210,b ≈ 1.107. Proyección paraN=10: alrededor de 11.280 tokens. - Spring Boot con JPA:
a ≈ 250,b ≈ 1.264. Proyección paraN=10: alrededor de 12.890 tokens. - NestJS con Prisma:
a ≈ 75,b ≈ 1.318. Proyección paraN=10: alrededor de 13.255 tokens. - Bun con Hono y Drizzle:
a ≈ 230,b ≈ 1.357. Proyección paraN=10: alrededor de 13.800 tokens. - C# con ASP.NET Core y EF Core:
a ≈ 400,b ≈ 1.581. Proyección paraN=10: alrededor de 16.210 tokens.
La lectura es reveladora. Django y Laravel mantienen el liderazgo en cualquier N porque tienen las pendientes b más bajas de la tabla, consecuencia directa de convenciones fuertes (ModelViewSet de DRF, Route::apiResource de Laravel). C# con ASP.NET, por otro lado, tiene la b más alta — cada nueva entidad exige DTO de creación, DTO de actualización, DTO de lectura, validaciones en cada uno y configuraciones en el DbContext. En proyectos grandes, la diferencia entre el primero y el último supera las dos veces y media el consumo de tokens.
NestJS es otro caso interesante: quedó en sexto con N=1, pero su b es alta. Cada nueva entidad exige module, controller, service, dto de creación, dto de actualización, interface, model y schema. En proyectos con pocas entidades, NestJS es competitivo; en sistemas grandes, la pendiente cobra el precio y tiende a superar tanto a Spring Boot como a Go.
Este modelo lineal se sostiene mientras las entidades viven aisladas unas de otras. Cuando empiezan a relacionarse entre sí y la IA tiene que describir esas relaciones para generar código consistente, el análisis cambia. Si cada una de las N entidades puede tener relación con cada una de las otras, describir el grafo completo crece en el peor caso con O(N²). En la práctica, los sistemas reales tienen pocos hubs muy conectados y muchas entidades casi aisladas, así que el crecimiento queda entre O(N) y O(N²), típicamente más cerca de lo lineal.
Otro costo entra en juego cuando el sistema crece: el mantenimiento. Cada nueva modificación exige que el modelo cargue parte del código existente como contexto, para no romper invariantes que ya están allí. Ese contexto también escala con N. El costo total de propiedad del código generado por IA tiene dos términos: el de generación inicial y el de cada iteración posterior, ambos creciendo con N. Los stacks que minimizan tokens por entidad reducen los dos al mismo tiempo, y la ganancia se compone con cada iteración.
Por último, existe un techo absoluto. Los modelos tienen ventana de contexto finita. Cuando el código existente excede esa ventana, la IA tiene que elegir qué leer, y esa selección tiene su propio costo. Los stacks que entregan contexto denso, con pocos archivos y baja indirección, preservan más tokens para la nueva regla de negocio. Los stacks fragmentados en muchos archivos obligan al modelo a leer más para entregar la misma cantidad de razonamiento efectivo.
“En proyectos largos, la pendientebimporta más que el punto de partidaa.”
En proyectos con expectativa de vida larga y docenas de entidades, elegir un stack con b bajo paga dividendos compuestos en cada iteración. En proyectos pequeños o pruebas de concepto, la diferencia es marginal y otros factores como DX, familiaridad del equipo y ecosistema suelen dominar la decisión.
Adherencia del código generado
Tokens gastados no es lo mismo que valor entregado. Un código que gasta pocos tokens pero necesita ser reescrito antes de funcionar termina costando mucho más a lo largo del ciclo. Para captar ese otro eje, revisamos línea por línea el output de cada stack y clasificamos cuánto retrabajo sería necesario para que el código se vuelva funcional.
- Laravel: adherencia alta. Convenciones respetadas, Route::apiResource correcto, Eloquent con fillable y casts idiomáticos, FormRequest con reglas válidas. Funcionaría con ajustes mínimos.
- Django con DRF: adherencia alta. ModelViewSet correcto, DefaultRouter idiomático, ModelSerializer con Meta apropiado. Pequeña corrección puntual en el UUIDField default (debería ser uuid.uuid4) y organización de carpetas que mezcla models/views/serializers fuera del patrón de app único.
- Go con Gin y GORM: adherencia alta. Estructura idiomática, separación clara entre handlers, services y routes. Pequeños ajustes puntuales como imports faltantes de strconv en la paginación.
- Spring Boot con JPA: adherencia media-alta. Entity correcta con Jakarta Persistence, Repository limpio, Service idiomático. Inconsistencia en el archivo de configuración (mezcla javax.persistence con jakarta.persistence) que requeriría ajuste en proyectos Spring Boot 3+.
- C# con ASP.NET Core: adherencia alta. Estructura idiomática completa. El único bug es el atributo [Index(IsUnique = true)] en propiedad, que en EF Core moderno se configura vía Fluent API. El resto del código funciona con ajustes mínimos.
- Bun con Elysia y Drizzle: adherencia media. Estructura limpia de Elysia, pero Drizzle aún salió con pequeñas inconsistencias de API en algunos runs (withCount, sintaxis de pgEnum). Necesita revisión puntual en el service.
- Go con Fiber y Ent: adherencia media. Conceptos correctos, pero el modelo dejó paths literales en algunos archivos y la cadena de update está mal encadenada. Imports incompletos en handlers de update.
- Bun con Hono y Drizzle: adherencia media. Estructura correcta de ruteo Hono, sin confundir con otros runtimes. Pequeños detalles de import y schema que piden revisión.
- NestJS con Prisma: adherencia media. Prisma se generó correctamente esta vez, con schema.prisma y PrismaService. Validación vía class-validator presente. Algunas inconsistencias en el try/catch estandarizado que podrían volverse un filtro global.
Vale notar que esta adherencia depende fuertemente del tamaño del modelo. Los modelos pequeños, con menos parámetros, tienden a alucinar en frameworks de cola larga — las librerías menos populares aparecen poco en el dato de entrenamiento y el modelo recurre a sintaxis de librerías vecinas mejor documentadas. Con Qwen 2.5 Coder 14B ese efecto fue raro; con modelos menores, es común ver Hono cambiado por Next.js o Prisma cambiado por Mongoose en la generación de CRUD.
“El costo efectivo de un stack es tokens de generación más tokens de retrabajo. En modelos pequeños, los stacks con poca documentación en el entrenamiento pagan el segundo término silenciosamente.”
Este eje confirma la lectura del benchmark. Django y Laravel no solo gastaron menos tokens, también entregaron outputs cercanos a funcional. C# fue el más verboso, pero también entregó código altamente estructurado y casi listo. Los stacks en el medio de la tabla exigen ajustes pequeños, esperables en cualquier generación de código con IA en este momento.
Lo que dice Anthropic al respecto
Este razonamiento no es solo la opinión de quien usa IA en el día a día. En un artículo reciente sobre Claude Code en grandes bases de código, la propia Anthropic refuerza que el entorno del modelo importa más que el modelo aislado.
“El ecosistema construido alrededor del modelo, el harness, determina el rendimiento de Claude Code más que el modelo por sí solo.”
Traducido al debate de stacks: el framework, sus convenciones, el ORM elegido y la arquitectura por defecto funcionan como el harness del modelo. Esa capa decide si la IA gasta tokens entendiendo tu estructura o avanzando en la lógica de negocio.
“La capacidad de Claude para ayudar en una base de código grande está limitada por su capacidad de encontrar el contexto correcto.”
Stacks concisos como Bun con Elysia y Drizzle entregan esa legibilidad de forma natural: pocos archivos, tipos inferidos y baja indirección. Los frameworks más opinados compensan con convenciones fuertes, pero el precio se paga en tokens por archivo.
“Demasiado contexto cargado en cada sesión degrada el rendimiento; muy poco contexto deja a Claude navegando a ciegas.”
El punto es directo: existe un equilibrio. Los stacks que minimizan el ruido estructural dejan más espacio para lo que importa, sin caer en el extremo opuesto de exigir contexto adicional en cada prompt.
Qué stack elegir
La elección depende de cuál sea la prioridad principal del proyecto. Algunas combinaciones funcionan mejor en escenarios específicos.
- Prioridad en menor consumo de tokens: Django con DRF o Laravel.
- Prioridad en productividad y madurez: Laravel o Django.
- Prioridad en type safety moderno: Bun con Elysia y Drizzle.
- Prioridad en rendimiento y binarios simples: Go con Fiber y Ent.
- Prioridad en arquitectura corporativa JVM: Spring Boot con JPA.
- Prioridad en integración con el ecosistema Microsoft: ASP.NET Core con Entity Framework.
- Prioridad en arquitectura previsible en TypeScript: NestJS con Prisma.
Mi recomendación
Para proyectos donde el objetivo es entregar valor de negocio rápido con IA escribiendo buena parte del código, Django con DRF y Laravel terminaron técnicamente empatados en el tope del benchmark — la diferencia de 44 tokens entre ellos es ruido. La elección entre los dos pasa por la familiaridad del equipo y el ecosistema preferido, no por el consumo. Ambos combinan el menor consumo de tokens del benchmark con convenciones fuertes que reducen la probabilidad de que el modelo se pierda en el camino.
Cuando la prioridad es tipado moderno de extremo a extremo, un runtime de alto rendimiento y un equipo que vive en TypeScript, Bun con Elysia y Drizzle sigue siendo una opción fuerte. Quedó en tercer lugar en consumo de tokens, entrega inferencia de tipos de extremo a extremo que ninguna otra stack del benchmark ofrece, y continúa siendo una apuesta sólida para equipos que quieren huir del peso del Node tradicional.
Para proyectos enterprise con restricciones de stack (JVM o .NET por cuestiones corporativas), Spring Boot y ASP.NET Core entregan código estructurado y funcional, con el costo esperado en tokens. No es razonable esperar que estas plataformas, diseñadas en torno al tipado fuerte y la separación rígida de responsabilidades, lideren un ranking de concisión — pero la ganancia de previsibilidad es lo que justifica el consumo.
Conclusión
Al utilizar IA para el desarrollo, el consumo de tokens se convierte en un factor estratégico, no solo un detalle técnico. Los stacks más concisos reducen el costo, aceleran la generación, simplifican las iteraciones y liberan contexto para las reglas de negocio.
“El mejor stack es aquel que maximiza la productividad del equipo y permite que la IA enfoque su esfuerzo en la lógica que diferencia el producto.”
Django con DRF y Laravel terminaron técnicamente empatados en el tope, ambos combinando convenciones maduras, un ecosistema robusto y el menor consumo de tokens entre las stacks evaluadas — combinación difícil de superar para proyectos que necesitan acelerar la entrega con apoyo de IA. Bun con Elysia y Drizzle viene justo detrás, con la ventaja adicional de tipado moderno y un runtime de alto rendimiento para equipos que viven en TypeScript. En el otro extremo, ASP.NET Core mostró que el costo del estilo enterprise puede llegar a casi tres veces el de un framework de CRUD especializado — una decisión a tomar conscientemente.
Limitaciones de este análisis
Los números presentados arriba fueron producidos por un modelo específico en condiciones específicas, y es importante dejarlo transparente para que el lector pueda interpretar los resultados con la calibración correcta.
- Modelo utilizado: Qwen 2.5 Coder 14B, ejecutándose localmente vía Ollama en un MacBook Pro M3 con 18GB de memoria. Modelos comerciales más grandes como Claude Opus, GPT-5 o Gemini Ultra pueden generar código más elaborado y, por lo tanto, más tokens en términos absolutos. El ranking entre stacks tiende a preservarse, pero los valores absolutos no son intercambiables.
- Cada familia de modelos tiene su propio tokenizer. Los conteos reportados aquí reflejan el tokenizer de Qwen y no son directamente comparables con Claude, GPT o Gemini para la misma porción de código. Lo que se mantiene consistente entre tokenizers es el ranking relativo.
- Cada stack se generó tres veces para calcular la mediana. Los runs de una misma stack quedaron en una franja estrecha de variación, lo que vuelve la mediana estable y el ranking confiable.
- Los coeficientes
aybde la sección de complejidad son estimaciones derivadas de la proporción entre archivos fijos y archivos por entidad en el benchmark de una entidad. Validar esas proyecciones requeriría ejecutar el benchmark conNvariados (próximo ciclo). - El costo total de propiedad también depende del talento disponible, el soporte del ecosistema y los costos operativos fuera de la generación de código.
Próximos pasos
El próximo ciclo de este benchmark va a responder las preguntas que aún quedaron abiertas.
- Ejecutar el mismo prompt en Claude, GPT y Gemini para comparar el ranking entre tokenizers comerciales y medir si las posiciones se mantienen con modelos de frontera.
- Validar empíricamente la fórmula
T(N) ≈ a + b × Nejecutando el benchmark conNvariando entre una y diez entidades, midiendoaybrealmente en vez de estimar. - Medir el tiempo hasta el primer despliegue local, ejecutando el código generado en cada stack, instalando dependencias y levantando el servidor con la base de datos.
- Medir el costo de mantenimiento: cuántos tokens gasta cada stack al agregar un campo nuevo a la entidad, no solo al crear desde cero.
- Ampliar a stacks aún no cubiertas: Rails, FastAPI, Phoenix, Quarkus.
- Evaluar cómo se comporta cada stack en iteraciones a largo plazo, simulando seis meses de evolución de producto.
Si tú también estás utilizando IA para acelerar el desarrollo, esta comparación puede ayudarte a elegir un stack más eficiente y alineado con la estrategia tecnológica de tu producto.
Glosario
Términos técnicos usados a lo largo del artículo, en orden de aparición:
CRUD— sigla de Create, Read, Update, Delete. Las cuatro operaciones básicas que toda aplicación realiza sobre datos persistidos.REST— estilo arquitectural de API que usa verbos HTTP (GET, POST, PUT, DELETE) y URLs como recursos.Endpoint— URL específica de una API que acepta peticiones y devuelve respuestas.Boilerplate— código repetitivo que toda feature necesita pero no contiene regla de negocio (configuración, imports, scaffolding).ORM— Object-Relational Mapping. Librería que traduce operaciones sobre objetos del lenguaje en consultas SQL sobre la base de datos.Migration— script versionado que altera el schema de la base de datos de forma controlada y reversible.DTO— Data Transfer Object. Objeto diseñado específicamente para transportar datos entre capas o por la red, sin comportamiento.Decoradores— sintaxis que aplica metadatos o comportamiento a una clase, método o propiedad. Existe en TypeScript, Python, Java, C# y otros.Tokenizer— algoritmo que parte el texto en unidades menores (tokens) antes de que el modelo lo procese. Cada familia de modelos tiene el suyo, y los conteos no son intercambiables.Harness— conjunto de herramientas, prompts de sistema e infraestructura que rodea a un modelo de IA para volverlo útil en una aplicación real. Incluye lectura de archivos, gestión de contexto y las herramientas disponibles para el modelo. En el debate de stacks de este artículo, los frameworks y sus convenciones funcionan como el harness de la IA al generar código.Ventana de contexto— cantidad máxima de tokens que un modelo acepta en una sola llamada, sumando el prompt enviado y la respuesta generada.Big O— notación que describe cómo el tiempo o el consumo de una operación crece a medida que la entrada aumenta.O(N)es crecimiento lineal,O(N²)es cuadrático.Pendiente— en una recta de la formay = a + b × x,bes la pendiente: cuánto creceypor cada unidad quexaumenta.
